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