Merge branch 'jims_annotate3d_update' into menard_finalsep2012
[jalview.git] / src / jalview / io / StockholmFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)\r
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  *  \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 /*\r
19  * This extension was written by Benjamin Schuster-Boeckler at sanger.ac.uk\r
20  */\r
21 package jalview.io;\r
22 \r
23 import jalview.datamodel.AlignmentAnnotation;\r
24 import jalview.datamodel.Annotation;\r
25 import jalview.datamodel.Sequence;\r
26 import jalview.datamodel.SequenceFeature;\r
27 import jalview.datamodel.SequenceI;\r
28 \r
29 import java.io.BufferedReader;\r
30 import java.io.FileReader;\r
31 import java.io.IOException;\r
32 import java.util.ArrayList;\r
33 import java.util.Enumeration;\r
34 import java.util.Hashtable;\r
35 import java.util.StringTokenizer;\r
36 import java.util.Vector;\r
37 \r
38 import com.stevesoft.pat.Regex;\r
39 \r
40 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;\r
41 import fr.orsay.lri.varna.factories.RNAFactory;\r
42 import fr.orsay.lri.varna.models.rna.RNA;\r
43 \r
44 // import org.apache.log4j.*;\r
45 \r
46 /**\r
47  * This class is supposed to parse a Stockholm format file into Jalview There\r
48  * are TODOs in this class: we do not know what the database source and version\r
49  * is for the file when parsing the #GS= AC tag which associates accessions with\r
50  * sequences. Database references are also not parsed correctly: a separate\r
51  * reference string parser must be added to parse the database reference form\r
52  * into Jalview's local representation.\r
53  * \r
54  * @author bsb at sanger.ac.uk\r
55  * @version 0.3 + jalview mods\r
56  * \r
57  */\r
58 public class StockholmFile extends AlignFile\r
59 {\r
60   // static Logger logger = Logger.getLogger("jalview.io.StockholmFile");\r
61   protected ArrayList<RNA> result;\r
62 \r
63   public String id;\r
64 \r
65   public StockholmFile()\r
66   {\r
67   }\r
68 \r
69   public StockholmFile(String inFile, String type) throws IOException\r
70   {\r
71     super(inFile, type);\r
72   }\r
73 \r
74   public StockholmFile(FileParse source) throws IOException\r
75   {\r
76     super(source);\r
77   }\r
78 \r
79   public void initData()\r
80   {\r
81     super.initData();\r
82   }\r
83 \r
84   /**\r
85    * Parse a file in Stockholm format into Jalview's data model. The file has to\r
86    * be passed at construction time\r
87    * \r
88    * @throws IOException\r
89    *           If there is an error with the input file\r
90    */\r
91   public void parse() throws IOException\r
92   {\r
93       StringBuffer treeString = new StringBuffer();\r
94       String treeName = null;\r
95       // --------------- Variable Definitions -------------------\r
96       String line;\r
97       String version;\r
98       String id;\r
99       Hashtable seqAnn = new Hashtable(); // Sequence related annotations\r
100       Hashtable seqs = new Hashtable();\r
101       Regex p, r, rend, s, x;\r
102       // Temporary line for processing RNA annotation\r
103       // String RNAannot = "";\r
104 \r
105       // ------------------ Parsing File ----------------------\r
106       // First, we have to check that this file has STOCKHOLM format, i.e. the\r
107       // first line must match\r
108       \r
109   \r
110                 r = new Regex("# STOCKHOLM ([\\d\\.]+)");\r
111                 if (!r.search(nextLine()))\r
112                 {\r
113                         throw new IOException(\r
114                                         "This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'");\r
115                 }\r
116                 else\r
117                 {\r
118                         version = r.stringMatched(1);\r
119                 \r
120                         // logger.debug("Stockholm version: " + version);\r
121                 }\r
122 \r
123                 // We define some Regexes here that will be used regularily later\r
124                 rend = new Regex("^\\s*\\/\\/"); // Find the end of an alignment\r
125                 p = new Regex("(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in\r
126                 // id/from/to\r
127                 s = new Regex("(\\S+)\\s+(\\S*)\\s+(.*)"); // Parses annotation subtype\r
128                 r = new Regex("#=(G[FSRC]?)\\s+(.*)"); // Finds any annotation line\r
129                 x = new Regex("(\\S+)\\s+(\\S+)"); // split id from sequence\r
130 \r
131                 // Convert all bracket types to parentheses (necessary for passing to VARNA)\r
132                 Regex openparen = new Regex("(<|\\[)", "(");\r
133                 Regex closeparen = new Regex("(>|\\])", ")");\r
134 \r
135                 // Detect if file is RNA by looking for bracket types\r
136                 Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");\r
137 \r
138                 rend.optimize();\r
139             p.optimize();\r
140             s.optimize();\r
141             r.optimize();\r
142             x.optimize();\r
143             openparen.optimize();\r
144             closeparen.optimize();\r
145         \r
146             while ((line = nextLine()) != null)\r
147             {\r
148               if (line.length() == 0)\r
149               {\r
150                 continue;\r
151               }\r
152               if (rend.search(line))\r
153               {\r
154                 // End of the alignment, pass stuff back\r
155         \r
156                 this.noSeqs = seqs.size();\r
157                 // logger.debug("Number of sequences: " + this.noSeqs);\r
158                 Enumeration accs = seqs.keys();\r
159                 while (accs.hasMoreElements())\r
160                 {\r
161                   String acc = (String) accs.nextElement();\r
162                   // logger.debug("Processing sequence " + acc);\r
163                   String seq = (String) seqs.remove(acc);\r
164                   if (maxLength < seq.length())\r
165                   {\r
166                     maxLength = seq.length();\r
167                   }\r
168                   int start = 1;\r
169                   int end = -1;\r
170                   String sid = acc;\r
171                   /*\r
172                    * Retrieve hash of annotations for this accession\r
173                    * Associate Annotation with accession\r
174                    */\r
175                   Hashtable accAnnotations = null;\r
176         \r
177                   if (seqAnn != null && seqAnn.containsKey(acc))\r
178                   {\r
179                     accAnnotations = (Hashtable) seqAnn.remove(acc);\r
180                     //TODO: add structures to sequence\r
181                   }\r
182         \r
183                   // Split accession in id and from/to\r
184                   if (p.search(acc))\r
185                   {\r
186                     sid = p.stringMatched(1);\r
187                     start = Integer.parseInt(p.stringMatched(2));\r
188                     end = Integer.parseInt(p.stringMatched(3));\r
189                   }\r
190                   // logger.debug(sid + ", " + start + ", " + end);\r
191         \r
192                   Sequence seqO = new Sequence(sid, seq, start, end);\r
193                   // Add Description (if any)\r
194                   if (accAnnotations != null && accAnnotations.containsKey("DE"))\r
195                   {\r
196                     String desc = (String) accAnnotations.get("DE");\r
197                     seqO.setDescription((desc == null) ? "" : desc);\r
198                   }\r
199                   // Add DB References (if any)\r
200                   if (accAnnotations != null && accAnnotations.containsKey("DR"))\r
201                   {\r
202                     String dbr = (String) accAnnotations.get("DR");\r
203                     if (dbr != null && dbr.indexOf(";") > -1)\r
204                     {\r
205                       String src = dbr.substring(0, dbr.indexOf(";"));\r
206                       String acn = dbr.substring(dbr.indexOf(";") + 1);\r
207                       jalview.util.DBRefUtils.parseToDbRef(seqO, src, "0", acn);\r
208                       // seqO.addDBRef(dbref);\r
209                     }\r
210                   }        \r
211                   if (accAnnotations != null && accAnnotations.containsKey("SS"))\r
212                   {\r
213                           Vector v = (Vector) accAnnotations.get("SS");\r
214                           \r
215                           for (int i = 0; i < v.size(); i++)\r
216                             {\r
217                                   AlignmentAnnotation an = (AlignmentAnnotation) v.elementAt(i);\r
218                                   seqO.addAlignmentAnnotation(an);\r
219                                   //annotations.add(an);\r
220                             }\r
221                   }\r
222                 \r
223                   Hashtable features = null;\r
224                   // We need to adjust the positions of all features to account for gaps\r
225                   try\r
226                   {\r
227                     features = (Hashtable) accAnnotations.remove("features");\r
228                   } catch (java.lang.NullPointerException e)\r
229                   {\r
230                     // loggerwarn("Getting Features for " + acc + ": " +\r
231                     // e.getMessage());\r
232                     // continue;\r
233                   }\r
234                   // if we have features\r
235                   if (features != null)\r
236                   {\r
237                     int posmap[] = seqO.findPositionMap();\r
238                     Enumeration i = features.keys();\r
239                     while (i.hasMoreElements())\r
240                     {\r
241                       // TODO: parse out secondary structure annotation as annotation\r
242                       // row\r
243                       // TODO: parse out scores as annotation row\r
244                       // TODO: map coding region to core jalview feature types\r
245                       String type = i.nextElement().toString();\r
246                       Hashtable content = (Hashtable) features.remove(type);\r
247                       Enumeration j = content.keys();\r
248                       while (j.hasMoreElements())\r
249                       {\r
250                         String desc = j.nextElement().toString();\r
251                         String ns = content.get(desc).toString();\r
252                         char[] byChar = ns.toCharArray();\r
253                         for (int k = 0; k < byChar.length; k++)\r
254                         {\r
255                           char c = byChar[k];\r
256                           if (!(c == ' ' || c == '_' || c == '-' || c == '.')) // PFAM\r
257                           // uses\r
258                           // '.'\r
259                           // for\r
260                           // feature\r
261                           // background\r
262                           {\r
263                             int new_pos = posmap[k]; // look up nearest seqeunce\r
264                             // position to this column\r
265                             SequenceFeature feat = new SequenceFeature(type, desc,\r
266                                     new_pos, new_pos, 0f, null);\r
267         \r
268                             seqO.addSequenceFeature(feat);\r
269                           }\r
270                         }\r
271                       }\r
272         \r
273                     }\r
274         \r
275                   }\r
276                   // garbage collect\r
277         \r
278                   // logger.debug("Adding seq " + acc + " from " + start + " to " + end\r
279                   // + ": " + seq);\r
280                   this.seqs.addElement(seqO);\r
281                 }\r
282                 return; // finished parsing this segment of source\r
283               }\r
284               else if (!r.search(line))\r
285               {\r
286                 // System.err.println("Found sequence line: " + line);\r
287         \r
288                 // Split sequence in sequence and accession parts\r
289                 if (!x.search(line))\r
290                 {\r
291                   // logger.error("Could not parse sequence line: " + line);\r
292                   throw new IOException("Could not parse sequence line: " + line);\r
293                 }\r
294                 String ns = (String) seqs.get(x.stringMatched(1));\r
295                 if (ns == null)\r
296                 {\r
297                   ns = "";\r
298                 }\r
299                 ns += x.stringMatched(2);\r
300         \r
301                 seqs.put(x.stringMatched(1), ns);\r
302               }\r
303               else\r
304               {\r
305                 String annType = r.stringMatched(1);\r
306                 String annContent = r.stringMatched(2);\r
307         \r
308                 // System.err.println("type:" + annType + " content: " + annContent);\r
309         \r
310                 if (annType.equals("GF"))\r
311                 {\r
312                   /*\r
313                    * Generic per-File annotation, free text Magic features: #=GF NH\r
314                    * <tree in New Hampshire eXtended format> #=GF TN <Unique identifier\r
315                    * for the next tree> Pfam descriptions: 7. DESCRIPTION OF FIELDS\r
316                    * \r
317                    * Compulsory fields: ------------------\r
318                    * \r
319                    * AC Accession number: Accession number in form PFxxxxx.version or\r
320                    * PBxxxxxx. ID Identification: One word name for family. DE\r
321                    * Definition: Short description of family. AU Author: Authors of the\r
322                    * entry. SE Source of seed: The source suggesting the seed members\r
323                    * belong to one family. GA Gathering method: Search threshold to\r
324                    * build the full alignment. TC Trusted Cutoff: Lowest sequence score\r
325                    * and domain score of match in the full alignment. NC Noise Cutoff:\r
326                    * Highest sequence score and domain score of match not in full\r
327                    * alignment. TP Type: Type of family -- presently Family, Domain,\r
328                    * Motif or Repeat. SQ Sequence: Number of sequences in alignment. AM\r
329                    * Alignment Method The order ls and fs hits are aligned to the model\r
330                    * to build the full align. // End of alignment.\r
331                    * \r
332                    * Optional fields: ----------------\r
333                    * \r
334                    * DC Database Comment: Comment about database reference. DR Database\r
335                    * Reference: Reference to external database. RC Reference Comment:\r
336                    * Comment about literature reference. RN Reference Number: Reference\r
337                    * Number. RM Reference Medline: Eight digit medline UI number. RT\r
338                    * Reference Title: Reference Title. RA Reference Author: Reference\r
339                    * Author RL Reference Location: Journal location. PI Previous\r
340                    * identifier: Record of all previous ID lines. KW Keywords: Keywords.\r
341                    * CC Comment: Comments. NE Pfam accession: Indicates a nested domain.\r
342                    * NL Location: Location of nested domains - sequence ID, start and\r
343                    * end of insert.\r
344                    * \r
345                    * Obsolete fields: ----------- AL Alignment method of seed: The\r
346                    * method used to align the seed members.\r
347                    */\r
348                   // Let's save the annotations, maybe we'll be able to do something\r
349                   // with them later...\r
350                   Regex an = new Regex("(\\w+)\\s*(.*)");\r
351                   if (an.search(annContent))\r
352                   {\r
353                     if (an.stringMatched(1).equals("NH"))\r
354                     {\r
355                       treeString.append(an.stringMatched(2));\r
356                     }\r
357                     else if (an.stringMatched(1).equals("TN"))\r
358                     {\r
359                       if (treeString.length() > 0)\r
360                       {\r
361                         if (treeName == null)\r
362                         {\r
363                           treeName = "Tree " + (getTreeCount() + 1);\r
364                         }\r
365                         addNewickTree(treeName, treeString.toString());\r
366                       }\r
367                       treeName = an.stringMatched(2);\r
368                       treeString = new StringBuffer();\r
369                     }\r
370                     setAlignmentProperty(an.stringMatched(1), an.stringMatched(2));\r
371                   }\r
372                 }\r
373                 else if (annType.equals("GS"))\r
374                 {\r
375                   // Generic per-Sequence annotation, free text\r
376                   /*\r
377                    * Pfam uses these features: Feature Description ---------------------\r
378                    * ----------- AC <accession> ACcession number DE <freetext>\r
379                    * DEscription DR <db>; <accession>; Database Reference OS <organism>\r
380                    * OrganiSm (species) OC <clade> Organism Classification (clade, etc.)\r
381                    * LO <look> Look (Color, etc.)\r
382                    */\r
383                   if (s.search(annContent))\r
384                   {\r
385                     String acc = s.stringMatched(1);\r
386                     String type = s.stringMatched(2);\r
387                     String content = s.stringMatched(3);\r
388                     // TODO: store DR in a vector.\r
389                     // TODO: store AC according to generic file db annotation.\r
390                     Hashtable ann;\r
391                     if (seqAnn.containsKey(acc))\r
392                     {\r
393                       ann = (Hashtable) seqAnn.get(acc);\r
394                     }\r
395                     else\r
396                     {\r
397                       ann = new Hashtable();\r
398                     }\r
399                     ann.put(type, content);\r
400                     seqAnn.put(acc, ann);\r
401                   }\r
402                   else\r
403                   {\r
404                     throw new IOException("Error parsing " + line);\r
405                   }\r
406                 }\r
407                 else if (annType.equals("GC"))\r
408                 {\r
409                   // Generic per-Column annotation, exactly 1 char per column\r
410                   // always need a label.\r
411                   if (x.search(annContent))\r
412                   {\r
413                     // parse out and create alignment annotation directly.\r
414                     parseAnnotationRow(annotations, x.stringMatched(1),\r
415                             x.stringMatched(2));\r
416                   }\r
417                 }\r
418                 else if (annType.equals("GR"))\r
419                 {\r
420                   // Generic per-Sequence AND per-Column markup, exactly 1 char per\r
421                   // column\r
422                   /*\r
423                    * Feature Description Markup letters ------- -----------\r
424                    * -------------- SS Secondary Structure [HGIEBTSCX] SA Surface\r
425                    * Accessibility [0-9X] (0=0%-10%; ...; 9=90%-100%) TM TransMembrane\r
426                    * [Mio] PP Posterior Probability [0-9*] (0=0.00-0.05; 1=0.05-0.15;\r
427                    * *=0.95-1.00) LI LIgand binding [*] AS Active Site [*] IN INtron (in\r
428                    * or after) [0-2]\r
429                    */\r
430                   if (s.search(annContent))\r
431                   {\r
432                     String acc = s.stringMatched(1);\r
433                     String type = s.stringMatched(2);\r
434                     String seq = new String(s.stringMatched(3));\r
435                     String description = null;\r
436                     // Check for additional information about the current annotation\r
437                     // We use a simple string tokenizer here for speed\r
438                     StringTokenizer sep = new StringTokenizer(seq, " \t");\r
439                     description = sep.nextToken();\r
440                     if (sep.hasMoreTokens())\r
441                     {\r
442                       seq = sep.nextToken();\r
443                     }\r
444                     else\r
445                     {\r
446                       seq = description;\r
447                       description = new String();\r
448                     }\r
449                     // sequence id with from-to fields\r
450         \r
451                     Hashtable ann;\r
452                     // Get an object with all the annotations for this sequence\r
453                     if (seqAnn.containsKey(acc))\r
454                     {\r
455                       // logger.debug("Found annotations for " + acc);\r
456                       ann = (Hashtable) seqAnn.get(acc);\r
457                     }\r
458                     else\r
459                     {\r
460                       // logger.debug("Creating new annotations holder for " + acc);\r
461                       ann = new Hashtable();\r
462                       seqAnn.put(acc, ann);\r
463                     }\r
464                     //TODO test structure, call parseAnnotationRow with vector from hashtable for specific sequence\r
465                     Hashtable features;\r
466                     // Get an object with all the content for an annotation\r
467                     if (ann.containsKey("features"))\r
468                     {\r
469                       // logger.debug("Found features for " + acc);\r
470                       features = (Hashtable) ann.get("features");\r
471                     }\r
472                     else\r
473                     {\r
474                       // logger.debug("Creating new features holder for " + acc);\r
475                       features = new Hashtable();\r
476                       ann.put("features", features);\r
477                     }\r
478         \r
479                     Hashtable content;\r
480                     if (features.containsKey(this.id2type(type)))\r
481                     {\r
482                       // logger.debug("Found content for " + this.id2type(type));\r
483                       content = (Hashtable) features.get(this.id2type(type));\r
484                     }\r
485                     else\r
486                     {\r
487                       // logger.debug("Creating new content holder for " +\r
488                       // this.id2type(type));\r
489                       content = new Hashtable();\r
490                       features.put(this.id2type(type), content);\r
491                     }\r
492                     String ns = (String) content.get(description);\r
493                     if (ns == null)\r
494                     {\r
495                       ns = "";\r
496                     }\r
497                     ns += seq;\r
498                     content.put(description, ns);\r
499         
500                     if(type.equals("SS")){\r
501                         Hashtable strucAnn;\r
502                         if (seqAnn.containsKey(acc))\r
503                         {\r
504                           strucAnn = (Hashtable) seqAnn.get(acc);\r
505                         }\r
506                         else\r
507                         {\r
508                           strucAnn = new Hashtable();\r
509                         }\r
510                         \r
511                         Vector newStruc=new Vector();\r
512                         parseAnnotationRow(newStruc, type,ns);\r
513                         \r
514                         strucAnn.put(type, newStruc);\r
515                         seqAnn.put(acc, strucAnn);\r
516                      }\r
517                   }\r
518                         else\r
519                         {\r
520                                                 System.err\r
521                                                 .println("Warning - couldn't parse sequence annotation row line:\n"\r
522                                                 + line);\r
523                         // throw new IOException("Error parsing " + line);\r
524                         }\r
525                         }\r
526                         else\r
527                         {\r
528                         throw new IOException("Unknown annotation detected: " + annType\r
529                                 + " " + annContent);\r
530                         }\r
531                         }\r
532                 }\r
533                 if (treeString.length() > 0)\r
534                 {\r
535                 if (treeName == null)\r
536                 {\r
537                         treeName = "Tree " + (1 + getTreeCount());\r
538                 }\r
539                 addNewickTree(treeName, treeString.toString());\r
540                 }\r
541         }\r
542 \r
543 \r
544   /**\r
545    * Parse a file in Stockholm format into Jalview's data model using VARNA\r
546    * \r
547    * @throws IOException\r
548    *           If there is an error with the input file\r
549    */\r
550   public void parse_with_VARNA() throws IOException\r
551   {\r
552     FileReader fr = null;\r
553     fr = new FileReader(inFile);\r
554 \r
555     BufferedReader r = new BufferedReader(fr);\r
556     result = null;\r
557     try\r
558     {\r
559       result = RNAFactory.loadSecStrStockholm(r);\r
560     } catch (ExceptionUnmatchedClosingParentheses umcp)\r
561     {\r
562       errormessage = "Unmatched parentheses in annotation. Aborting ("\r
563               + umcp.getMessage() + ")";\r
564       throw new IOException(umcp);\r
565     }\r
566     // DEBUG System.out.println("this is the secondary scructure:"\r
567     // +result.size());\r
568     SequenceI[] seqs = new SequenceI[result.size()];\r
569     for (int i = 0; i < result.size(); i++)\r
570     {\r
571       // DEBUG System.err.println("Processing i'th sequence in Stockholm file")\r
572       RNA current = result.get(i);\r
573 \r
574       String seq = current.getSeq();\r
575       String rna = current.getStructDBN(true);\r
576       // DEBUG System.out.println(seq);\r
577       // DEBUG System.err.println(rna);\r
578       int begin = 0;\r
579       int end = seq.length() - 1;\r
580       id = safeName(getDataName());\r
581       seqs[i] = new Sequence(id, seq, begin, end);\r
582       String[] annot = new String[rna.length()];\r
583       Annotation[] ann = new Annotation[rna.length()];\r
584       for (int j = 0; j < rna.length(); j++)\r
585       {\r
586         annot[j] = rna.substring(j, j + 1);\r
587 \r
588       }\r
589 \r
590       for (int k = 0; k < rna.length(); k++)\r
591       {\r
592         ann[k] = new Annotation(annot[k], "",\r
593                 jalview.schemes.ResidueProperties.getRNASecStrucState(\r
594                         annot[k]).charAt(0), 0f);\r
595 \r
596       }\r
597       AlignmentAnnotation align = new AlignmentAnnotation("Sec. str.",\r
598               current.getID(), ann);\r
599 \r
600       seqs[i].addAlignmentAnnotation(align);\r
601       seqs[i].setRNA(result.get(i));\r
602       this.annotations.addElement(align);\r
603     }\r
604     this.setSeqs(seqs);\r
605 \r
606   }\r
607 \r
608   protected static AlignmentAnnotation parseAnnotationRow(\r
609           Vector annotation, String label, String annots)\r
610   {\r
611     String convert1, convert2 = null;\r
612 \r
613     // Convert all bracket types to parentheses\r
614     Regex openparen = new Regex("(<|\\[)", "(");\r
615     Regex closeparen = new Regex("(>|\\])", ")");\r
616 \r
617     // Detect if file is RNA by looking for bracket types\r
618     Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");\r
619 \r
620     convert1 = openparen.replaceAll(annots);\r
621     convert2 = closeparen.replaceAll(convert1);\r
622     annots = convert2;\r
623 \r
624     String type = (label.indexOf("_cons") == label.length() - 5) ? label\r
625             .substring(0, label.length() - 5) : label;\r
626     boolean ss = false;\r
627     type = id2type(type);\r
628     if (type.equals("secondary structure"))\r
629     {\r
630       ss = true;\r
631     }\r
632     // decide on secondary structure or not.\r
633     Annotation[] els = new Annotation[annots.length()];\r
634     for (int i = 0; i < annots.length(); i++)\r
635     {\r
636       String pos = annots.substring(i, i + 1);\r
637       Annotation ann;\r
638       ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not\r
639       // be written out\r
640       if (ss)\r
641       {\r
642         if (detectbrackets.search(pos))\r
643         {\r
644           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
645                   .getRNASecStrucState(pos).charAt(0);\r
646         }\r
647         else\r
648         {\r
649           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
650                   .getDssp3state(pos).charAt(0);\r
651         }\r
652 \r
653         if (ann.secondaryStructure == pos.charAt(0) || pos.charAt(0) == 'C')\r
654         {\r
655           ann.displayCharacter = ""; // null; // " ";\r
656         }\r
657         else\r
658         {\r
659           ann.displayCharacter = " " + ann.displayCharacter;\r
660         }\r
661       }\r
662 \r
663       els[i] = ann;\r
664     }\r
665     AlignmentAnnotation annot = null;\r
666     Enumeration e = annotation.elements();\r
667     while (e.hasMoreElements())\r
668     {\r
669       annot = (AlignmentAnnotation) e.nextElement();\r
670       if (annot.label.equals(type))\r
671         break;\r
672       annot = null;\r
673     }\r
674     if (annot == null)\r
675     {\r
676       annot = new AlignmentAnnotation(type, type, els);\r
677       annotation.addElement(annot);\r
678     }\r
679     else\r
680     {\r
681       Annotation[] anns = new Annotation[annot.annotations.length\r
682               + els.length];\r
683       System.arraycopy(annot.annotations, 0, anns, 0,\r
684               annot.annotations.length);\r
685       System.arraycopy(els, 0, anns, annot.annotations.length, els.length);\r
686       annot.annotations = anns;\r
687       // System.out.println("else: ");\r
688     }\r
689     return annot;\r
690   }\r
691 \r
692   public static String print(SequenceI[] s)\r
693   {\r
694     return "not yet implemented";\r
695   }\r
696 \r
697   public String print()\r
698   {\r
699     return print(getSeqsAsArray());\r
700   }\r
701 \r
702   private static Hashtable typeIds = null;\r
703   static\r
704   {\r
705     if (typeIds == null)\r
706     {\r
707       typeIds = new Hashtable();\r
708       typeIds.put("SS", "secondary structure");\r
709       typeIds.put("SA", "surface accessibility");\r
710       typeIds.put("TM", "transmembrane");\r
711       typeIds.put("PP", "posterior probability");\r
712       typeIds.put("LI", "ligand binding");\r
713       typeIds.put("AS", "active site");\r
714       typeIds.put("IN", "intron");\r
715       typeIds.put("IR", "interacting residue");\r
716       typeIds.put("AC", "accession");\r
717       typeIds.put("OS", "organism");\r
718       typeIds.put("CL", "class");\r
719       typeIds.put("DE", "description");\r
720       typeIds.put("DR", "reference");\r
721       typeIds.put("LO", "look");\r
722       typeIds.put("RF", "reference positions");\r
723 \r
724     }\r
725   }\r
726 \r
727   protected static String id2type(String id)\r
728   {\r
729     if (typeIds.containsKey(id))\r
730     {\r
731       return (String) typeIds.get(id);\r
732     }\r
733     System.err.println("Warning : Unknown Stockholm annotation type code "\r
734             + id);\r
735     return id;\r
736   }\r
737   /**\r
738    * make a friendly ID string.\r
739    * \r
740    * @param dataName\r
741    * @return truncated dataName to after last '/'\r
742    */\r
743   private String safeName(String dataName)\r
744   {\r
745     int b = 0;\r
746     while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())\r
747     {\r
748       dataName = dataName.substring(b + 1).trim();\r
749 \r
750     }\r
751     int e = (dataName.length() - dataName.indexOf(".")) + 1;\r
752     dataName = dataName.substring(1, e).trim();\r
753     return dataName;\r
754   }\r
755 }\r