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