JAL-3691 automatic insertion of Locale.ROOT to toUpperCase() and toLowerCase() and...
[jalview.git] / src / jalview / io / MSFfile.java
index 7c70a09..e954703 100755 (executable)
@@ -1,27 +1,37 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
- * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
  *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  * PURPOSE.  See the GNU General Public License for more details.
  * 
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.io;
 
-import java.io.*;
-import java.util.*;
+import java.util.Locale;
 
-import jalview.datamodel.*;
-import jalview.util.*;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
+import jalview.util.Format;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.StringTokenizer;
 
 /**
  * DOCUMENT ME!
@@ -50,7 +60,7 @@ public class MSFfile extends AlignFile
    * @throws IOException
    *           DOCUMENT ME!
    */
-  public MSFfile(String inFile, String type) throws IOException
+  public MSFfile(String inFile, DataSourceType type) throws IOException
   {
     super(inFile, type);
   }
@@ -60,28 +70,24 @@ public class MSFfile extends AlignFile
     super(source);
   }
 
-  {
-    // TODO Auto-generated constructor stub
-  }
-
   /**
-   * DOCUMENT ME!
+   * Read and parse MSF sequence data
    */
+  @Override
   public void parse() throws IOException
   {
-    int i = 0;
     boolean seqFlag = false;
-    String key = new String();
-    Vector headers = new Vector();
-    Hashtable seqhash = new Hashtable();
-    String line;
+    List<String> headers = new ArrayList<String>();
+    Hashtable<String, StringBuilder> seqhash = new Hashtable<String, StringBuilder>();
 
     try
     {
+      String line;
       while ((line = nextLine()) != null)
       {
         StringTokenizer str = new StringTokenizer(line);
 
+        String key = null;
         while (str.hasMoreTokens())
         {
           String inStr = str.nextToken();
@@ -90,31 +96,31 @@ public class MSFfile extends AlignFile
           if (inStr.indexOf("Name:") != -1)
           {
             key = str.nextToken();
-            headers.addElement(key);
+            headers.add(key);
           }
 
-          // if line has // set SeqFlag to 1 so we know sequences are coming
+          // if line has // set SeqFlag so we know sequences are coming
           if (inStr.indexOf("//") != -1)
           {
             seqFlag = true;
           }
 
           // Process lines as sequence lines if seqFlag is set
-          if ((inStr.indexOf("//") == -1) && (seqFlag == true))
+          if ((inStr.indexOf("//") == -1) && seqFlag)
           {
-            // seqeunce id is the first field
+            // sequence id is the first field
             key = inStr;
 
-            StringBuffer tempseq;
+            StringBuilder tempseq;
 
             // Get sequence from hash if it exists
             if (seqhash.containsKey(key))
             {
-              tempseq = (StringBuffer) seqhash.get(key);
+              tempseq = seqhash.get(key);
             }
             else
             {
-              tempseq = new StringBuffer();
+              tempseq = new StringBuilder(64);
               seqhash.put(key, tempseq);
             }
 
@@ -122,7 +128,8 @@ public class MSFfile extends AlignFile
             while (str.hasMoreTokens())
             {
               // append the word to the sequence
-              tempseq.append(str.nextToken());
+              String sequenceBlock = str.nextToken();
+              tempseq.append(sequenceBlock);
             }
           }
         }
@@ -136,11 +143,11 @@ public class MSFfile extends AlignFile
     this.noSeqs = headers.size();
 
     // Add sequences to the hash
-    for (i = 0; i < headers.size(); i++)
+    for (int i = 0; i < headers.size(); i++)
     {
-      if (seqhash.get(headers.elementAt(i)) != null)
+      if (seqhash.get(headers.get(i)) != null)
       {
-        String head = headers.elementAt(i).toString();
+        String head = headers.get(i);
         String seq = seqhash.get(head).toString();
 
         if (maxLength < head.length())
@@ -148,8 +155,11 @@ public class MSFfile extends AlignFile
           maxLength = head.length();
         }
 
-        // Replace ~ with a sensible gap character
-        seq = seq.replace('~', '-');
+        /*
+         * replace ~ (leading/trailing positions) with the gap character;
+         * use '.' as this is the internal gap character required by MSF
+         */
+        seq = seq.replace('~', '.');
 
         Sequence newSeq = parseId(head);
 
@@ -160,7 +170,7 @@ public class MSFfile extends AlignFile
       else
       {
         System.err.println("MSFFile Parser: Can't find sequence for "
-                + headers.elementAt(i));
+                + headers.get(i));
       }
     }
   }
@@ -176,7 +186,7 @@ public class MSFfile extends AlignFile
   public int checkSum(String seq)
   {
     int check = 0;
-    String sequence = seq.toUpperCase();
+    String sequence = seq.toUpperCase(Locale.ROOT);
 
     for (int i = 0; i < sequence.length(); i++)
     {
@@ -208,15 +218,17 @@ public class MSFfile extends AlignFile
    * 
    * @return DOCUMENT ME!
    */
-  public String print(SequenceI[] seqs)
+  @Override
+  public String print(SequenceI[] sqs, boolean jvSuffix)
   {
 
-    boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);
+    boolean is_NA = Comparison.isNucleotide(sqs);
 
-    SequenceI[] s = new SequenceI[seqs.length];
+    SequenceI[] s = new SequenceI[sqs.length];
 
-    StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA")
-            + "_MULTIPLE_ALIGNMENT 1.0");
+    StringBuilder out = new StringBuilder(256);
+    out.append("!!").append(is_NA ? "NA" : "AA")
+            .append("_MULTIPLE_ALIGNMENT 1.0");
     // TODO: JBPNote : Jalview doesn't remember NA or AA yet.
     out.append(newline);
     out.append(newline);
@@ -224,14 +236,15 @@ public class MSFfile extends AlignFile
     int maxid = 0;
     int i = 0;
 
-    while ((i < seqs.length) && (seqs[i] != null))
+    while ((i < sqs.length) && (sqs[i] != null))
     {
-      // Replace all internal gaps with . and external spaces with ~
-      s[i] = new Sequence(seqs[i].getName(), seqs[i].getSequenceAsString()
-              .replace('-', '.'), seqs[i].getStart(), seqs[i].getEnd());
+      /*
+       * modify to MSF format: uses '.' for internal gaps, 
+       * and '~' for leading or trailing gaps
+       */
+      String seqString = sqs[i].getSequenceAsString().replace('-', '.');
 
-      StringBuffer sb = new StringBuffer();
-      sb.append(s[i].getSequence());
+      StringBuilder sb = new StringBuilder(seqString);
 
       for (int ii = 0; ii < sb.length(); ii++)
       {
@@ -256,21 +269,21 @@ public class MSFfile extends AlignFile
           break;
         }
       }
+      s[i] = new Sequence(sqs[i].getName(), sb.toString(),
+              sqs[i].getStart(), sqs[i].getEnd());
 
-      s[i].setSequence(sb.toString());
-
-      if (s[i].getSequence().length > max)
+      if (sb.length() > max)
       {
-        max = s[i].getSequence().length;
+        max = sb.length();
       }
 
       i++;
     }
 
-    Format maxLenpad = new Format("%" + (new String("" + max)).length()
-            + "d");
-    Format maxChkpad = new Format("%" + (new String("1" + max)).length()
-            + "d");
+    Format maxLenpad = new Format(
+            "%" + (new String("" + max)).length() + "d");
+    Format maxChkpad = new Format(
+            "%" + (new String("1" + max)).length() + "d");
     i = 0;
 
     int bigChecksum = 0;
@@ -283,7 +296,7 @@ public class MSFfile extends AlignFile
     }
 
     long maxNB = 0;
-    out.append("   MSF: " + s[0].getSequence().length + "   Type: "
+    out.append("   MSF: " + s[0].getLength() + "   Type: "
             + (is_NA ? "N" : "P") + "    Check:  " + (bigChecksum % 10000)
             + "   ..");
     out.append(newline);
@@ -297,11 +310,11 @@ public class MSFfile extends AlignFile
     while ((i < s.length) && (s[i] != null))
     {
 
-      nameBlock[i] = new String("  Name: " + printId(s[i]) + " ");
+      nameBlock[i] = new String("  Name: " + printId(s[i], jvSuffix) + " ");
 
-      idBlock[i] = new String("Len: "
-              + maxLenpad.form(s[i].getSequence().length) + "  Check: "
-              + maxChkpad.form(checksums[i]) + "  Weight: 1.00" + newline);
+      idBlock[i] = new String("Len: " + maxLenpad.form(s[i].getLength())
+              + "  Check: " + maxChkpad.form(checksums[i])
+              + "  Weight: 1.00" + newline);
 
       if (s[i].getName().length() > maxid)
       {
@@ -341,12 +354,7 @@ public class MSFfile extends AlignFile
     out.append(newline);
     int len = 50;
 
-    int nochunks = (max / len) + 1;
-
-    if ((max % len) == 0)
-    {
-      nochunks--;
-    }
+    int nochunks = (max / len) + (max % len > 0 ? 1 : 0);
 
     for (i = 0; i < nochunks; i++)
     {
@@ -354,7 +362,7 @@ public class MSFfile extends AlignFile
 
       while ((j < s.length) && (s[j] != null))
       {
-        String name = printId(s[j]);
+        String name = printId(s[j], jvSuffix);
 
         out.append(new Format("%-" + maxid + "s").form(name + " "));
 
@@ -363,8 +371,9 @@ public class MSFfile extends AlignFile
           int start = (i * 50) + (k * 10);
           int end = start + 10;
 
-          if ((end < s[j].getSequence().length)
-                  && (start < s[j].getSequence().length))
+          int length = s[j].getLength();
+          if ((end < length)
+                  && (start < length))
           {
             out.append(s[j].getSequence(start, end));
 
@@ -379,7 +388,7 @@ public class MSFfile extends AlignFile
           }
           else
           {
-            if (start < s[j].getSequence().length)
+            if (start < length)
             {
               out.append(s[j].getSequenceAsString().substring(start));
               out.append(newline);
@@ -402,14 +411,4 @@ public class MSFfile extends AlignFile
 
     return out.toString();
   }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public String print()
-  {
-    return print(getSeqsAsArray());
-  }
 }