2cf0572986c50cd8bba7812ed24dd38b23b26251
[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.text.DateFormat;
45 import java.text.DecimalFormat;
46 import java.text.DecimalFormatSymbols;
47 import java.text.NumberFormat;
48 import java.text.ParseException;
49 import java.text.SimpleDateFormat;
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.Date;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Map.Entry;
57 import java.util.Set;
58 import java.util.SortedMap;
59 import java.util.SortedSet;
60 import java.util.TreeMap;
61 import java.util.TreeSet;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
64
65 import org.forester.archaeopteryx.Constants;
66 import org.forester.phylogeny.PhylogenyNode;
67 import org.forester.phylogeny.data.Distribution;
68 import org.forester.phylogeny.data.Sequence;
69 import org.forester.phylogeny.data.Taxonomy;
70 import org.forester.protein.BasicProtein;
71 import org.forester.protein.Domain;
72 import org.forester.protein.Protein;
73 import org.forester.surfacing.SurfacingUtil;
74
75 public final class ForesterUtil {
76
77     public final static String       FILE_SEPARATOR                   = System.getProperty( "file.separator" );
78     public final static String       LINE_SEPARATOR                   = System.getProperty( "line.separator" );
79     public final static String       JAVA_VENDOR                      = System.getProperty( "java.vendor" );
80     public final static String       JAVA_VERSION                     = System.getProperty( "java.version" );
81     public final static String       OS_ARCH                          = System.getProperty( "os.arch" );
82     public final static String       OS_NAME                          = System.getProperty( "os.name" );
83     public final static String       OS_VERSION                       = System.getProperty( "os.version" );
84     public final static Pattern      PARANTHESESABLE_NH_CHARS_PATTERN = Pattern.compile( "[(),;\\s]" );
85     public final static double       ZERO_DIFF                        = 1.0E-9;
86     public static final BigDecimal   NULL_BD                          = new BigDecimal( 0 );
87     public static final NumberFormat FORMATTER_9;
88     public static final NumberFormat FORMATTER_6;
89     public static final NumberFormat FORMATTER_06;
90     public static final NumberFormat FORMATTER_3;
91     public static final String       NCBI_PROTEIN                     = "http://www.ncbi.nlm.nih.gov/protein/";
92     public static final String       NCBI_NUCCORE                     = "http://www.ncbi.nlm.nih.gov/nuccore/";
93     public final static String       UNIPROT_KB                       = "http://www.uniprot.org/uniprot/";
94     public static final String       NCBI_GI                          = "http://www.ncbi.nlm.nih.gov/protein/gi:";
95     static {
96         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
97         dfs.setDecimalSeparator( '.' );
98         // dfs.setGroupingSeparator( ( char ) 0 );
99         FORMATTER_9 = new DecimalFormat( "#.#########", dfs );
100         FORMATTER_6 = new DecimalFormat( "#.######", dfs );
101         FORMATTER_06 = new DecimalFormat( "0.######", dfs );
102         FORMATTER_3 = new DecimalFormat( "#.###", dfs );
103     }
104
105     private ForesterUtil() {
106     }
107
108     public static int calculateOverlap( final Domain domain, final List<Boolean> covered_positions ) {
109         int overlap_count = 0;
110         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
111             if ( ( i < covered_positions.size() ) && ( covered_positions.get( i ) == true ) ) {
112                 ++overlap_count;
113             }
114         }
115         return overlap_count;
116     }
117
118     final public static void appendSeparatorIfNotEmpty( final StringBuffer sb, final char separator ) {
119         if ( sb.length() > 0 ) {
120             sb.append( separator );
121         }
122     }
123
124     /**
125      * 
126      * Example regarding engulfment: ------------0.1 ----------0.2 --0.3 =>
127      * domain with 0.3 is ignored
128      * 
129      * -----------0.1 ----------0.2 --0.3 => domain with 0.3 is ignored
130      * 
131      * 
132      * ------------0.1 ----------0.3 --0.2 => domains with 0.3 and 0.2 are _not_
133      * ignored
134      * 
135      * @param max_allowed_overlap
136      *            maximal allowed overlap (inclusive) to be still considered not
137      *            overlapping (zero or negative value to allow any overlap)
138      * @param remove_engulfed_domains
139      *            to remove domains which are completely engulfed by coverage of
140      *            domains with better support
141      * @param protein
142      * @return
143      */
144     public static Protein removeOverlappingDomains( final int max_allowed_overlap,
145                                                     final boolean remove_engulfed_domains,
146                                                     final Protein protein ) {
147         final Protein pruned_protein = new BasicProtein( protein.getProteinId().getId(), protein.getSpecies()
148                 .getSpeciesId(), protein.getLength() );
149         final List<Domain> sorted = SurfacingUtil.sortDomainsWithAscendingConfidenceValues( protein );
150         final List<Boolean> covered_positions = new ArrayList<Boolean>();
151         for( final Domain domain : sorted ) {
152             if ( ( ( max_allowed_overlap < 0 ) || ( ForesterUtil.calculateOverlap( domain, covered_positions ) <= max_allowed_overlap ) )
153                     && ( !remove_engulfed_domains || !isEngulfed( domain, covered_positions ) ) ) {
154                 final int covered_positions_size = covered_positions.size();
155                 for( int i = covered_positions_size; i < domain.getFrom(); ++i ) {
156                     covered_positions.add( false );
157                 }
158                 final int new_covered_positions_size = covered_positions.size();
159                 for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
160                     if ( i < new_covered_positions_size ) {
161                         covered_positions.set( i, true );
162                     }
163                     else {
164                         covered_positions.add( true );
165                     }
166                 }
167                 pruned_protein.addProteinDomain( domain );
168             }
169         }
170         return pruned_protein;
171     }
172
173     /**
174      * Returns true is Domain domain falls in an uninterrupted stretch of
175      * covered positions.
176      * 
177      * @param domain
178      * @param covered_positions
179      * @return
180      */
181     public static boolean isEngulfed( final Domain domain, final List<Boolean> covered_positions ) {
182         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
183             if ( ( i >= covered_positions.size() ) || ( covered_positions.get( i ) != true ) ) {
184                 return false;
185             }
186         }
187         return true;
188     }
189
190     /**
191      * This calculates a color. If value is equal to min the returned color is
192      * minColor, if value is equal to max the returned color is maxColor,
193      * otherwise a color 'proportional' to value is returned.
194      * 
195      * @param value
196      *            the value 
197      * @param min
198      *            the smallest value 
199      * @param max
200      *            the largest value 
201      * @param minColor
202      *            the color for min
203      * @param maxColor
204      *            the color for max
205      * @return a Color
206      */
207     final public static Color calcColor( double value,
208                                          final double min,
209                                          final double max,
210                                          final Color minColor,
211                                          final Color maxColor ) {
212         if ( value < min ) {
213             value = min;
214         }
215         if ( value > max ) {
216             value = max;
217         }
218         final double x = ForesterUtil.calculateColorFactor( value, max, min );
219         final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), maxColor.getRed(), x );
220         final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), maxColor.getGreen(), x );
221         final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), maxColor.getBlue(), x );
222         return new Color( red, green, blue );
223     }
224
225     /**
226      * This calculates a color. If value is equal to min the returned color is
227      * minColor, if value is equal to max the returned color is maxColor, if
228      * value is equal to mean the returned color is meanColor, otherwise a color
229      * 'proportional' to value is returned -- either between min-mean or
230      * mean-max
231      * 
232      * @param value
233      *            the value
234      * @param min
235      *            the smallest value
236      * @param max
237      *            the largest value 
238      * @param mean
239      *            the mean/median value 
240      * @param minColor
241      *            the color for min
242      * @param maxColor
243      *            the color for max
244      * @param meanColor
245      *            the color for mean
246      * @return a Color
247      */
248     final public static Color calcColor( double value,
249                                          final double min,
250                                          final double max,
251                                          final double mean,
252                                          final Color minColor,
253                                          final Color maxColor,
254                                          final Color meanColor ) {
255         if ( value < min ) {
256             value = min;
257         }
258         if ( value > max ) {
259             value = max;
260         }
261         if ( value < mean ) {
262             final double x = ForesterUtil.calculateColorFactor( value, mean, min );
263             final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), meanColor.getRed(), x );
264             final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), meanColor.getGreen(), x );
265             final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), meanColor.getBlue(), x );
266             return new Color( red, green, blue );
267         }
268         else if ( value > mean ) {
269             final double x = ForesterUtil.calculateColorFactor( value, max, mean );
270             final int red = ForesterUtil.calculateColorComponent( meanColor.getRed(), maxColor.getRed(), x );
271             final int green = ForesterUtil.calculateColorComponent( meanColor.getGreen(), maxColor.getGreen(), x );
272             final int blue = ForesterUtil.calculateColorComponent( meanColor.getBlue(), maxColor.getBlue(), x );
273             return new Color( red, green, blue );
274         }
275         else {
276             return meanColor;
277         }
278     }
279
280     final public static String collapseWhiteSpace( final String s ) {
281         return s.replaceAll( "[\\s]+", " " );
282     }
283
284     final public static void collection2file( final File file, final Collection<?> data, final String separator )
285             throws IOException {
286         final Writer writer = new BufferedWriter( new FileWriter( file ) );
287         collection2writer( writer, data, separator );
288         writer.close();
289     }
290
291     final public static void collection2writer( final Writer writer, final Collection<?> data, final String separator )
292             throws IOException {
293         boolean first = true;
294         for( final Object object : data ) {
295             if ( !first ) {
296                 writer.write( separator );
297             }
298             else {
299                 first = false;
300             }
301             writer.write( object.toString() );
302         }
303     }
304
305     final public static String colorToHex( final Color color ) {
306         final String rgb = Integer.toHexString( color.getRGB() );
307         return rgb.substring( 2, rgb.length() );
308     }
309
310     synchronized public static void copyFile( final File in, final File out ) throws IOException {
311         final FileInputStream in_s = new FileInputStream( in );
312         final FileOutputStream out_s = new FileOutputStream( out );
313         try {
314             final byte[] buf = new byte[ 1024 ];
315             int i = 0;
316             while ( ( i = in_s.read( buf ) ) != -1 ) {
317                 out_s.write( buf, 0, i );
318             }
319         }
320         catch ( final IOException e ) {
321             throw e;
322         }
323         finally {
324             if ( in_s != null ) {
325                 in_s.close();
326             }
327             if ( out_s != null ) {
328                 out_s.close();
329             }
330         }
331     }
332
333     final public static int countChars( final String str, final char c ) {
334         int count = 0;
335         for( int i = 0; i < str.length(); ++i ) {
336             if ( str.charAt( i ) == c ) {
337                 ++count;
338             }
339         }
340         return count;
341     }
342
343     final public static BufferedWriter createBufferedWriter( final File file ) throws IOException {
344         if ( file.exists() ) {
345             throw new IOException( "[" + file + "] already exists" );
346         }
347         return new BufferedWriter( new FileWriter( file ) );
348     }
349
350     final public static BufferedWriter createBufferedWriter( final String name ) throws IOException {
351         return new BufferedWriter( new FileWriter( createFileForWriting( name ) ) );
352     }
353
354     final public static EasyWriter createEasyWriter( final File file ) throws IOException {
355         return new EasyWriter( createBufferedWriter( file ) );
356     }
357
358     final public static BufferedWriter createEasyWriter( final String name ) throws IOException {
359         return createEasyWriter( createFileForWriting( name ) );
360     }
361
362     final public static File createFileForWriting( final String name ) throws IOException {
363         final File file = new File( name );
364         if ( file.exists() ) {
365             throw new IOException( "[" + name + "] already exists" );
366         }
367         return file;
368     }
369
370     final public static void ensurePresenceOfDate( final PhylogenyNode node ) {
371         if ( !node.getNodeData().isHasDate() ) {
372             node.getNodeData().setDate( new org.forester.phylogeny.data.Date() );
373         }
374     }
375
376     final public static void ensurePresenceOfDistribution( final PhylogenyNode node ) {
377         if ( !node.getNodeData().isHasDistribution() ) {
378             node.getNodeData().setDistribution( new Distribution( "" ) );
379         }
380     }
381
382     public static void ensurePresenceOfSequence( final PhylogenyNode node ) {
383         if ( !node.getNodeData().isHasSequence() ) {
384             node.getNodeData().setSequence( new Sequence() );
385         }
386     }
387
388     public static void ensurePresenceOfTaxonomy( final PhylogenyNode node ) {
389         if ( !node.getNodeData().isHasTaxonomy() ) {
390             node.getNodeData().setTaxonomy( new Taxonomy() );
391         }
392     }
393
394     public static void fatalError( final String message ) {
395         System.err.println();
396         System.err.println( "error: " + message );
397         System.err.println();
398         System.exit( -1 );
399     }
400
401     public static void fatalError( final String prg_name, final String message ) {
402         System.err.println();
403         System.err.println( "[" + prg_name + "] > " + message );
404         System.err.println();
405         System.exit( -1 );
406     }
407
408     public static void fatalErrorIfFileNotReadable( final File file ) {
409         final String error = isReadableFile( file );
410         if ( !isEmpty( error ) ) {
411             System.err.println();
412             System.err.println( "error: " + error );
413             System.err.println();
414             System.exit( -1 );
415         }
416     }
417
418     public static void fatalErrorIfFileNotReadable( final String prg_name, final File file ) {
419         final String error = isReadableFile( file );
420         if ( !isEmpty( error ) ) {
421             System.err.println();
422             System.err.println( "[" + prg_name + "] > " + error );
423             System.err.println();
424             System.exit( -1 );
425         }
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     public static String[][] file22dArray( 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                 list.add( str );
446             }
447         }
448         in.close();
449         final String[][] ary = new String[ list.size() ][ 2 ];
450         final Pattern pa = Pattern.compile( "(\\S+)\\s+(\\S+)" );
451         int i = 0;
452         for( final String s : list ) {
453             final Matcher m = pa.matcher( s );
454             if ( m.matches() ) {
455                 ary[ i ][ 0 ] = m.group( 1 );
456                 ary[ i ][ 1 ] = m.group( 2 );
457                 ++i;
458             }
459             else {
460                 throw new IOException( "unexpcted format: " + s );
461             }
462         }
463         return ary;
464     }
465
466     final public static List<String> file2list( final File file ) throws IOException {
467         final List<String> list = new ArrayList<String>();
468         final BufferedReader in = new BufferedReader( new FileReader( file ) );
469         String str;
470         while ( ( str = in.readLine() ) != null ) {
471             str = str.trim();
472             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
473                 for( final String s : splitString( str ) ) {
474                     list.add( s );
475                 }
476             }
477         }
478         in.close();
479         return list;
480     }
481
482     final public static SortedSet<String> file2set( final File file ) throws IOException {
483         final SortedSet<String> set = new TreeSet<String>();
484         final BufferedReader in = new BufferedReader( new FileReader( file ) );
485         String str;
486         while ( ( str = in.readLine() ) != null ) {
487             str = str.trim();
488             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
489                 for( final String s : splitString( str ) ) {
490                     set.add( s );
491                 }
492             }
493         }
494         in.close();
495         return set;
496     }
497
498     final public static String getCurrentDateTime() {
499         final DateFormat format = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
500         return format.format( new Date() );
501     }
502
503     final public static String getFileSeparator() {
504         return ForesterUtil.FILE_SEPARATOR;
505     }
506
507     final public static String getFirstLine( final Object source ) throws FileNotFoundException, IOException {
508         BufferedReader reader = null;
509         if ( source instanceof File ) {
510             final File f = ( File ) source;
511             if ( !f.exists() ) {
512                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
513             }
514             else if ( !f.isFile() ) {
515                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
516             }
517             else if ( !f.canRead() ) {
518                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
519             }
520             reader = new BufferedReader( new FileReader( f ) );
521         }
522         else if ( source instanceof InputStream ) {
523             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
524         }
525         else if ( source instanceof String ) {
526             reader = new BufferedReader( new StringReader( ( String ) source ) );
527         }
528         else if ( source instanceof StringBuffer ) {
529             reader = new BufferedReader( new StringReader( source.toString() ) );
530         }
531         else if ( source instanceof URL ) {
532             reader = new BufferedReader( new InputStreamReader( ( ( URL ) source ).openStream() ) );
533         }
534         else {
535             throw new IllegalArgumentException( "dont know how to read [" + source.getClass() + "]" );
536         }
537         String line;
538         while ( ( line = reader.readLine() ) != null ) {
539             line = line.trim();
540             if ( !ForesterUtil.isEmpty( line ) ) {
541                 if ( reader != null ) {
542                     reader.close();
543                 }
544                 return line;
545             }
546         }
547         if ( reader != null ) {
548             reader.close();
549         }
550         return line;
551     }
552
553     final public static String getForesterLibraryInformation() {
554         return "forester " + ForesterConstants.FORESTER_VERSION + " (" + ForesterConstants.FORESTER_DATE + ")";
555     }
556
557     final public static String getLineSeparator() {
558         return ForesterUtil.LINE_SEPARATOR;
559     }
560
561     final public static void increaseCountingMap( final Map<String, Integer> counting_map, final String item_name ) {
562         if ( !counting_map.containsKey( item_name ) ) {
563             counting_map.put( item_name, 1 );
564         }
565         else {
566             counting_map.put( item_name, counting_map.get( item_name ) + 1 );
567         }
568     }
569
570     final public static boolean isContainsParanthesesableNhCharacter( final String nh ) {
571         return PARANTHESESABLE_NH_CHARS_PATTERN.matcher( nh ).find();
572     }
573
574     final public static boolean isEmpty( final List<?> l ) {
575         if ( ( l == null ) || l.isEmpty() ) {
576             return true;
577         }
578         for( final Object o : l ) {
579             if ( o != null ) {
580                 return false;
581             }
582         }
583         return true;
584     }
585
586     final public static boolean isEmpty( final Set<?> s ) {
587         if ( ( s == null ) || s.isEmpty() ) {
588             return true;
589         }
590         for( final Object o : s ) {
591             if ( o != null ) {
592                 return false;
593             }
594         }
595         return true;
596     }
597
598     final public static boolean isEmpty( final String s ) {
599         return ( ( s == null ) || ( s.length() < 1 ) );
600     }
601
602     final public static boolean isEqual( final double a, final double b ) {
603         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
604     }
605
606     final public static boolean isEven( final int n ) {
607         return ( n % 2 ) == 0;
608     }
609
610     /**
611      * This determines whether String[] a and String[] b have at least one
612      * String in common (intersect). Returns false if at least one String[] is
613      * null or empty.
614      * 
615      * @param a
616      *            a String[] b a String[]
617      * @return true if both a and b or not empty or null and contain at least
618      *         one element in common false otherwise
619      */
620     final public static boolean isIntersecting( final String[] a, final String[] b ) {
621         if ( ( a == null ) || ( b == null ) ) {
622             return false;
623         }
624         if ( ( a.length < 1 ) || ( b.length < 1 ) ) {
625             return false;
626         }
627         for( final String ai : a ) {
628             for( final String element : b ) {
629                 if ( ( ai != null ) && ( element != null ) && ai.equals( element ) ) {
630                     return true;
631                 }
632             }
633         }
634         return false;
635     }
636
637     final public static double isLargerOrEqualToZero( final double d ) {
638         if ( d > 0.0 ) {
639             return d;
640         }
641         else {
642             return 0.0;
643         }
644     }
645
646     final public static boolean isNull( final BigDecimal s ) {
647         return ( ( s == null ) || ( s.compareTo( NULL_BD ) == 0 ) );
648     }
649
650     final public static String isReadableFile( final File f ) {
651         if ( !f.exists() ) {
652             return "file [" + f + "] does not exist";
653         }
654         if ( f.isDirectory() ) {
655             return "[" + f + "] is a directory";
656         }
657         if ( !f.isFile() ) {
658             return "[" + f + "] is not a file";
659         }
660         if ( !f.canRead() ) {
661             return "file [" + f + "] is not readable";
662         }
663         if ( f.length() < 1 ) {
664             return "file [" + f + "] is empty";
665         }
666         return null;
667     }
668
669     final public static String isReadableFile( final String s ) {
670         return isReadableFile( new File( s ) );
671     }
672
673     public final static boolean isWindows() {
674         try {
675             return OS_NAME.toLowerCase().indexOf( "win" ) > -1;
676         }
677         catch ( final Exception e ) {
678             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
679             return false;
680         }
681     }
682
683     public final static boolean isMac() {
684         try {
685             return OS_NAME.toLowerCase().startsWith( "mac" );
686         }
687         catch ( final Exception e ) {
688             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
689             return false;
690         }
691     }
692
693     final public static String isWritableFile( final File f ) {
694         if ( f.isDirectory() ) {
695             return "[" + f + "] is a directory";
696         }
697         if ( f.exists() ) {
698             return "[" + f + "] already exists";
699         }
700         return null;
701     }
702
703     /**
704      * Helper for method "stringToColor".
705      * <p>
706      * (Last modified: 12/20/03)
707      */
708     final public static int limitRangeForColor( int i ) {
709         if ( i > 255 ) {
710             i = 255;
711         }
712         else if ( i < 0 ) {
713             i = 0;
714         }
715         return i;
716     }
717
718     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List<?> list ) {
719         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
720         for( final Object key : list ) {
721             if ( !map.containsKey( key ) ) {
722                 map.put( key, 1 );
723             }
724             else {
725                 map.put( key, map.get( key ) + 1 );
726             }
727         }
728         return map;
729     }
730
731     final public static void map2file( final File file,
732                                        final Map<?, ?> data,
733                                        final String entry_separator,
734                                        final String data_separator ) throws IOException {
735         final Writer writer = new BufferedWriter( new FileWriter( file ) );
736         map2writer( writer, data, entry_separator, data_separator );
737         writer.close();
738     }
739
740     final public static void map2writer( final Writer writer,
741                                          final Map<?, ?> data,
742                                          final String entry_separator,
743                                          final String data_separator ) throws IOException {
744         boolean first = true;
745         for( final Entry<?, ?> entry : data.entrySet() ) {
746             if ( !first ) {
747                 writer.write( data_separator );
748             }
749             else {
750                 first = false;
751             }
752             writer.write( entry.getKey().toString() );
753             writer.write( entry_separator );
754             writer.write( entry.getValue().toString() );
755         }
756     }
757
758     final public static StringBuffer mapToStringBuffer( final Map<Object, Object> map, final String key_value_separator ) {
759         final StringBuffer sb = new StringBuffer();
760         for( final Iterator<Object> iter = map.keySet().iterator(); iter.hasNext(); ) {
761             final Object key = iter.next();
762             sb.append( key.toString() );
763             sb.append( key_value_separator );
764             sb.append( map.get( key ).toString() );
765             sb.append( ForesterUtil.getLineSeparator() );
766         }
767         return sb;
768     }
769
770     final public static String normalizeString( final String s,
771                                                 final int length,
772                                                 final boolean left_pad,
773                                                 final char pad_char ) {
774         if ( s.length() > length ) {
775             return s.substring( 0, length );
776         }
777         else {
778             final StringBuffer pad = new StringBuffer( length - s.length() );
779             for( int i = 0; i < ( length - s.length() ); ++i ) {
780                 pad.append( pad_char );
781             }
782             if ( left_pad ) {
783                 return pad + s;
784             }
785             else {
786                 return s + pad;
787             }
788         }
789     }
790
791     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
792         BufferedReader reader = null;
793         if ( source instanceof File ) {
794             final File f = ( File ) source;
795             if ( !f.exists() ) {
796                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
797             }
798             else if ( !f.isFile() ) {
799                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
800             }
801             else if ( !f.canRead() ) {
802                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
803             }
804             reader = new BufferedReader( new FileReader( f ) );
805         }
806         else if ( source instanceof InputStream ) {
807             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
808         }
809         else if ( source instanceof String ) {
810             reader = new BufferedReader( new StringReader( ( String ) source ) );
811         }
812         else if ( source instanceof StringBuffer ) {
813             reader = new BufferedReader( new StringReader( source.toString() ) );
814         }
815         else {
816             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
817                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
818         }
819         return reader;
820     }
821
822     final public static StringBuffer pad( final double number, final int size, final char pad, final boolean left_pad ) {
823         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
824     }
825
826     final public static StringBuffer pad( final String string, final int size, final char pad, final boolean left_pad ) {
827         return pad( new StringBuffer( string ), size, pad, left_pad );
828     }
829
830     final public static StringBuffer pad( final StringBuffer string,
831                                           final int size,
832                                           final char pad,
833                                           final boolean left_pad ) {
834         final StringBuffer padding = new StringBuffer();
835         final int s = size - string.length();
836         if ( s < 1 ) {
837             return new StringBuffer( string.substring( 0, size ) );
838         }
839         for( int i = 0; i < s; ++i ) {
840             padding.append( pad );
841         }
842         if ( left_pad ) {
843             return padding.append( string );
844         }
845         else {
846             return string.append( padding );
847         }
848     }
849
850     final public static double parseDouble( final String str ) throws ParseException {
851         if ( ForesterUtil.isEmpty( str ) ) {
852             return 0.0;
853         }
854         return Double.parseDouble( str );
855     }
856
857     final public static int parseInt( final String str ) throws ParseException {
858         if ( ForesterUtil.isEmpty( str ) ) {
859             return 0;
860         }
861         return Integer.parseInt( str );
862     }
863
864     final public static void printArray( final Object[] a ) {
865         for( int i = 0; i < a.length; ++i ) {
866             System.out.println( "[" + i + "]=" + a[ i ] );
867         }
868     }
869
870     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
871         for( final String key : counting_map.keySet() ) {
872             System.out.println( key + ": " + counting_map.get( key ) );
873         }
874     }
875
876     final public static void printErrorMessage( final String prg_name, final String message ) {
877         System.err.println( "[" + prg_name + "] > error: " + message );
878     }
879
880     final public static void printProgramInformation( final String prg_name, final String prg_version, final String date ) {
881         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
882         System.out.println();
883         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
884         for( int i = 0; i < l; ++i ) {
885             System.out.print( "_" );
886         }
887         System.out.println();
888     }
889
890     final public static void printProgramInformation( final String prg_name,
891                                                       final String prg_version,
892                                                       final String date,
893                                                       final String email,
894                                                       final String www ) {
895         printProgramInformation( prg_name, null, prg_version, date, email, www, null );
896     }
897
898     final public static void printProgramInformation( final String prg_name,
899                                                       final String desc,
900                                                       final String prg_version,
901                                                       final String date,
902                                                       final String email,
903                                                       final String www,
904                                                       final String based_on ) {
905         String my_prg_name = new String( prg_name );
906         if ( !ForesterUtil.isEmpty( desc ) ) {
907             my_prg_name += ( " - " + desc );
908         }
909         final int l = my_prg_name.length() + prg_version.length() + date.length() + 4;
910         System.out.println();
911         System.out.println( my_prg_name + " " + prg_version + " (" + date + ")" );
912         for( int i = 0; i < l; ++i ) {
913             System.out.print( "_" );
914         }
915         System.out.println();
916         System.out.println();
917         System.out.println( "WWW     : " + www );
918         System.out.println( "Contact : " + email );
919         if ( !ForesterUtil.isEmpty( based_on ) ) {
920             System.out.println( "Based on: " + based_on );
921         }
922         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
923             System.out.println();
924             System.out.println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
925         }
926         System.out.println();
927     }
928
929     final public static void printWarningMessage( final String prg_name, final String message ) {
930         System.out.println( "[" + prg_name + "] > warning: " + message );
931     }
932
933     final public static void programMessage( final String prg_name, final String message ) {
934         System.out.println( "[" + prg_name + "] > " + message );
935     }
936
937     final public static String removeSuffix( final String file_name ) {
938         final int i = file_name.lastIndexOf( '.' );
939         if ( i > 1 ) {
940             return file_name.substring( 0, i );
941         }
942         return file_name;
943     }
944
945     /**
946      * Removes all white space from String s.
947      * 
948      * @return String s with white space removed
949      */
950     final public static String removeWhiteSpace( String s ) {
951         int i;
952         for( i = 0; i <= ( s.length() - 1 ); i++ ) {
953             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
954                     || ( s.charAt( i ) == '\r' ) ) {
955                 s = s.substring( 0, i ) + s.substring( i + 1 );
956                 i--;
957             }
958         }
959         return s;
960     }
961
962     final public static String replaceIllegalNhCharacters( final String nh ) {
963         if ( nh == null ) {
964             return "";
965         }
966         return nh.trim().replaceAll( "[\\[\\]:]+", "_" );
967     }
968
969     final public static String replaceIllegalNhxCharacters( final String nhx ) {
970         if ( nhx == null ) {
971             return "";
972         }
973         return nhx.trim().replaceAll( "[\\[\\](),:;\\s]+", "_" );
974     }
975
976     final public static double round( final double value, final int decimal_place ) {
977         BigDecimal bd = new BigDecimal( value );
978         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
979         return bd.doubleValue();
980     }
981
982     /**
983      * Rounds d to an int.
984      */
985     final public static int roundToInt( final double d ) {
986         return ( int ) ( d + 0.5 );
987     }
988
989     final public static int roundToInt( final float f ) {
990         return ( int ) ( f + 0.5f );
991     }
992
993     final public static short roundToShort( final double d ) {
994         return ( short ) ( d + 0.5 );
995     }
996
997     final public static String sanitizeString( final String s ) {
998         if ( s == null ) {
999             return "";
1000         }
1001         else {
1002             return s.trim();
1003         }
1004     }
1005
1006     public static boolean seqIsLikelyToBeAa( final String s ) {
1007         final String seq = s.toLowerCase();
1008         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
1009                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
1010                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
1011                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
1012             return true;
1013         }
1014         return false;
1015     }
1016
1017     final public static String stringArrayToString( final String[] a ) {
1018         return stringArrayToString( a, ", " );
1019     }
1020
1021     final public static String stringArrayToString( final String[] a, final String separator ) {
1022         final StringBuilder sb = new StringBuilder();
1023         if ( ( a != null ) && ( a.length > 0 ) ) {
1024             for( int i = 0; i < ( a.length - 1 ); ++i ) {
1025                 sb.append( a[ i ] + separator );
1026             }
1027             sb.append( a[ a.length - 1 ] );
1028         }
1029         return sb.toString();
1030     }
1031
1032     final public static String[] stringListToArray( final List<String> list ) {
1033         if ( list != null ) {
1034             final String[] str = new String[ list.size() ];
1035             int i = 0;
1036             for( final String l : list ) {
1037                 str[ i++ ] = l;
1038             }
1039             return str;
1040         }
1041         return null;
1042     }
1043
1044     final public static String stringListToString( final List<String> l, final String separator ) {
1045         final StringBuilder sb = new StringBuilder();
1046         if ( ( l != null ) && ( l.size() > 0 ) ) {
1047             for( int i = 0; i < ( l.size() - 1 ); ++i ) {
1048                 sb.append( l.get( i ) + separator );
1049             }
1050             sb.append( l.get( l.size() - 1 ) );
1051         }
1052         return sb.toString();
1053     }
1054
1055     final public static String[] stringSetToArray( final Set<String> strings ) {
1056         final String[] str_array = new String[ strings.size() ];
1057         int i = 0;
1058         for( final String e : strings ) {
1059             str_array[ i++ ] = e;
1060         }
1061         return str_array;
1062     }
1063
1064     final public static void unexpectedFatalError( final Exception e ) {
1065         System.err.println();
1066         System.err.println( "unexpected exception: should not have occured! Please contact program author(s)." );
1067         e.printStackTrace( System.err );
1068         System.err.println();
1069         System.exit( -1 );
1070     }
1071
1072     final public static void unexpectedFatalError( final Error e ) {
1073         System.err.println();
1074         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1075         e.printStackTrace( System.err );
1076         System.err.println();
1077         System.exit( -1 );
1078     }
1079
1080     final public static void unexpectedFatalError( final String message ) {
1081         System.err.println();
1082         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1083         System.err.println( message );
1084         System.err.println();
1085         System.exit( -1 );
1086     }
1087
1088     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
1089         System.err.println();
1090         System.err.println( "[" + prg_name
1091                 + "] > unexpected error; should not have occured! Please contact program author(s)." );
1092         e.printStackTrace( System.err );
1093         System.err.println();
1094         System.exit( -1 );
1095     }
1096
1097     final public static void unexpectedFatalError( final String prg_name, final String message ) {
1098         System.err.println();
1099         System.err.println( "[" + prg_name
1100                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1101         System.err.println( message );
1102         System.err.println();
1103         System.exit( -1 );
1104     }
1105
1106     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
1107         System.err.println();
1108         System.err.println( "[" + prg_name
1109                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1110         System.err.println( message );
1111         e.printStackTrace( System.err );
1112         System.err.println();
1113         System.exit( -1 );
1114     }
1115
1116     public final static void updateProgress( final double progress_percentage ) {
1117         final int width = 50;
1118         System.out.print( "\r[" );
1119         int i = 0;
1120         for( ; i <= ForesterUtil.roundToInt( progress_percentage * width ); i++ ) {
1121             System.out.print( "." );
1122         }
1123         for( ; i < width; i++ ) {
1124             System.out.print( " " );
1125         }
1126         System.out.print( "]" );
1127     }
1128
1129     public final static void updateProgress( final int i, final DecimalFormat f ) {
1130         System.out.print( "\r[" + f.format( i ) + "]" );
1131     }
1132
1133     public final static String wordWrap( final String str, final int width ) {
1134         final StringBuilder sb = new StringBuilder( str );
1135         int start = 0;
1136         int ls = -1;
1137         int i = 0;
1138         while ( i < sb.length() ) {
1139             if ( sb.charAt( i ) == ' ' ) {
1140                 ls = i;
1141             }
1142             if ( sb.charAt( i ) == '\n' ) {
1143                 ls = -1;
1144                 start = i + 1;
1145             }
1146             if ( i > ( ( start + width ) - 1 ) ) {
1147                 if ( ls != -1 ) {
1148                     sb.setCharAt( ls, '\n' );
1149                     start = ls + 1;
1150                     ls = -1;
1151                 }
1152                 else {
1153                     sb.insert( i, '\n' );
1154                     start = i + 1;
1155                 }
1156             }
1157             i++;
1158         }
1159         return sb.toString();
1160     }
1161
1162     /**
1163      * Helper method for calcColor methods.
1164      * 
1165      * @param smallercolor_component_x
1166      *            color component the smaller color
1167      * @param largercolor_component_x
1168      *            color component the larger color
1169      * @param x
1170      *            factor
1171      * @return an int representing a color component
1172      */
1173     final private static int calculateColorComponent( final double smallercolor_component_x,
1174                                                       final double largercolor_component_x,
1175                                                       final double x ) {
1176         return ( int ) ( smallercolor_component_x + ( ( x * ( largercolor_component_x - smallercolor_component_x ) ) / 255.0 ) );
1177     }
1178
1179     /**
1180      * Helper method for calcColor methods.
1181      * 
1182      * 
1183      * @param value
1184      *            the value
1185      * @param larger
1186      *            the largest value
1187      * @param smaller
1188      *            the smallest value
1189      * @return a normalized value between larger and smaller
1190      */
1191     final private static double calculateColorFactor( final double value, final double larger, final double smaller ) {
1192         return ( 255.0 * ( value - smaller ) ) / ( larger - smaller );
1193     }
1194
1195     final private static String[] splitString( final String str ) {
1196         final String regex = "[\\s;,]+";
1197         return str.split( regex );
1198     }
1199
1200     public final static void outOfMemoryError( final OutOfMemoryError e ) {
1201         System.err.println();
1202         System.err.println( "Java memory allocation might be too small, try \"-Xmx2048m\" java command line option" );
1203         System.err.println();
1204         e.printStackTrace( System.err );
1205         System.err.println();
1206         System.exit( -1 );
1207     }
1208
1209     public final static Color obtainColorDependingOnTaxonomyGroup( final String tax, final String tax_code ) {
1210         if ( tax.equalsIgnoreCase( "deuterostomia" ) ) {
1211             printRel( tax_code, "deuterostomia" );
1212             return TaxonomyColors.DEUTEROSTOMIA_COLOR;
1213         }
1214         else if ( tax.equalsIgnoreCase( "protostomia" ) ) {
1215             printRel( tax_code, "protostomia" );
1216             return TaxonomyColors.PROTOSTOMIA_COLOR;
1217         }
1218         else if ( tax.equalsIgnoreCase( "cnidaria" ) ) {
1219             printRel( tax_code, "cnidaria" );
1220             return TaxonomyColors.CNIDARIA_COLOR;
1221         }
1222         else if ( tax.toLowerCase().startsWith( "trichoplax" ) || tax.equalsIgnoreCase( "placozoa" ) ) {
1223             printRel( tax_code, "placozoa" );
1224             return TaxonomyColors.PLACOZOA_COLOR;
1225         }
1226         else if ( tax.toLowerCase().startsWith( "mnemiopsis" ) || tax.equalsIgnoreCase( "ctenophora" ) ) {
1227             printRel( tax_code, "ctenophora" );
1228             return TaxonomyColors.CTENOPHORA_COLOR;
1229         }
1230         else if ( tax.toLowerCase().startsWith( "amphimedon" ) || tax.equalsIgnoreCase( "porifera" ) ) {
1231             printRel( tax_code, "porifera" );
1232             return TaxonomyColors.PORIFERA_COLOR;
1233         }
1234         else if ( tax.equalsIgnoreCase( "codonosigidae" ) || tax.equalsIgnoreCase( "choanoflagellida" ) ) {
1235             printRel( tax_code, "choanoflagellida" );
1236             return TaxonomyColors.CHOANOFLAGELLIDA;
1237         }
1238         else if ( tax.toLowerCase().startsWith( "ichthyophonida & filasterea" )
1239                 || tax.toLowerCase().startsWith( "ichthyophonida and filasterea" )
1240                 || tax.toLowerCase().startsWith( "ichthyosporea & filasterea" )
1241                 || tax.toLowerCase().startsWith( "ichthyosporea and filasterea" ) ) {
1242             printRel( tax_code, "ichthyophonida & filasterea" );
1243             return TaxonomyColors.ICHTHYOSPOREA_AND_FILASTEREA;
1244         }
1245         else if ( tax.equalsIgnoreCase( "fungi" ) ) {
1246             printRel( tax_code, "fungi" );
1247             return TaxonomyColors.FUNGI_COLOR;
1248         }
1249         else if ( tax.toLowerCase().startsWith( "nucleariidae and fonticula" ) ) {
1250             printRel( tax_code, "nucleariidae and fonticula group" );
1251             return TaxonomyColors.NUCLEARIIDAE_AND_FONTICULA_GROUP_COLOR;
1252         }
1253         else if ( tax.equalsIgnoreCase( "amoebozoa" ) ) {
1254             printRel( tax_code, "amoebozoa" );
1255             return TaxonomyColors.AMOEBOZOA_COLOR;
1256         }
1257         else if ( tax.equalsIgnoreCase( "embryophyta" ) ) {
1258             printRel( tax_code, "embryophyta" );
1259             return TaxonomyColors.EMBRYOPHYTA_COLOR;
1260         }
1261         else if ( tax.equalsIgnoreCase( "chlorophyta" ) ) {
1262             printRel( tax_code, "chlorophyta" );
1263             return TaxonomyColors.CHLOROPHYTA_COLOR;
1264         }
1265         else if ( tax.equalsIgnoreCase( "rhodophyta" ) ) {
1266             printRel( tax_code, "rhodophyta" );
1267             return TaxonomyColors.RHODOPHYTA_COLOR;
1268         }
1269         else if ( tax.toLowerCase().startsWith( "hacrobia" ) ) {
1270             printRel( tax_code, "hacrobia" );
1271             return TaxonomyColors.HACROBIA_COLOR;
1272         }
1273         else if ( tax.equalsIgnoreCase( "glaucocystophyceae" ) || tax.equalsIgnoreCase( "glaucophyta" ) ) {
1274             printRel( tax_code, "glaucocystophyceae" );
1275             return TaxonomyColors.GLAUCOPHYTA_COLOR;
1276         }
1277         else if ( tax.equalsIgnoreCase( "stramenopiles" ) ) {
1278             printRel( tax_code, "stramenopiles" );
1279             return TaxonomyColors.STRAMENOPILES_COLOR;
1280         }
1281         else if ( tax.equalsIgnoreCase( "alveolata" ) ) {
1282             printRel( tax_code, "alveolata" );
1283             return TaxonomyColors.ALVEOLATA_COLOR;
1284         }
1285         else if ( tax.equalsIgnoreCase( "rhizaria" ) ) {
1286             printRel( tax_code, "rhizaria" );
1287             return TaxonomyColors.RHIZARIA_COLOR;
1288         }
1289         else if ( tax.equalsIgnoreCase( "excavata" ) ) {
1290             printRel( tax_code, "excavata" );
1291             return TaxonomyColors.EXCAVATA_COLOR;
1292         }
1293         else if ( tax.equalsIgnoreCase( "apusozoa" ) ) {
1294             printRel( tax_code, "apusozoa" );
1295             return TaxonomyColors.APUSOZOA_COLOR;
1296         }
1297         else if ( tax.equalsIgnoreCase( "archaea" ) ) {
1298             printRel( tax_code, "archaea" );
1299             return TaxonomyColors.ARCHAEA_COLOR;
1300         }
1301         else if ( tax.equalsIgnoreCase( "bacteria" ) ) {
1302             printRel( tax_code, "bacteria" );
1303             return TaxonomyColors.BACTERIA_COLOR;
1304         }
1305         return null;
1306     }
1307
1308     private final static void printRel( String tax_code, String group ) {
1309         //System.out.println( tax_code + "->" + group );
1310         System.out.println( "_default_taxcode_taxgroup_map.put( \"" + tax_code + "\", \"" + group + "\" );" );
1311     }
1312 }