JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / ext / edu / ucsf / rbvi / strucviz2 / ChimeraResidue.java
1 /* vim: set ts=2: */
2 /**
3  * Copyright (c) 2006 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions, and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions, and the following
13  *      disclaimer in the documentation and/or other materials provided
14  *      with the distribution.
15  *   3. Redistributions must acknowledge that this software was
16  *      originally developed by the UCSF Computer Graphics Laboratory
17  *      under support by the NIH National Center for Research Resources,
18  *      grant P41-RR01081.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 package ext.edu.ucsf.rbvi.strucviz2;
34
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * This class provides the implementation for the ChimeraResidue, object
44  * 
45  * @author scooter
46  * 
47  */
48
49 public class ChimeraResidue
50         implements ChimeraStructuralObject, Comparable<ChimeraResidue>
51 {
52
53   /* Constants */
54   public static final int SINGLE_LETTER = 0; // Display residues as a single
55                                              // letter
56
57   public static final int THREE_LETTER = 1; // Display residues as three letters
58
59   public static final int FULL_NAME = 2; // Display full residue names
60
61   private String type; // Residue type
62
63   private String index; // Residue index
64
65   private String chainId; // ChainID for this residue
66
67   private int modelNumber; // model number for this residue
68
69   private int subModelNumber; // sub-model number for this residue
70
71   protected int residueNumber;
72
73   protected String insertionCode;
74
75   private ChimeraModel chimeraModel; // ChimeraModel the residue is part of
76
77   private Object userData; // user data to associate with this residue
78
79   // public static HashMap<String, String> aaNames = null; // a map of amino
80   // acid
81   // names
82   private static int displayType = THREE_LETTER; // the current display type
83
84   private boolean selected = false; // the selection state
85
86   /**
87    * Constructor to create a new ChimeraResidue
88    * 
89    * @param type
90    *          the residue type
91    * @param index
92    *          the index of the residue
93    * @param modelNumber
94    *          the model number this residue is part of
95    */
96   public ChimeraResidue(String type, String index, int modelNumber)
97   {
98     this(type, index, modelNumber, 0);
99   }
100
101   /**
102    * Constructor to create a new ChimeraResidue
103    * 
104    * @param type
105    *          the residue type
106    * @param index
107    *          the index of the residue
108    * @param modelNumber
109    *          the model number this residue is part of
110    * @param subModelNumber
111    *          the sub-model number this residue is part of
112    */
113   public ChimeraResidue(String type, String index, int modelNumber,
114           int subModelNumber)
115   {
116     this.type = type;
117     this.index = index;
118     this.modelNumber = modelNumber;
119     this.subModelNumber = subModelNumber;
120     splitInsertionCode(this.index);
121     // if (aaNames == null) {
122     // initNames();
123     // }
124   }
125
126   /**
127    * Constructor to create a new ChimeraResidue from an input line
128    * 
129    * @param chimeraInputLine
130    *          a Chimera residue description
131    */
132   // invoked when listing (selected) residues: listr spec #0; lists level
133   // residue
134   // Line: residue id #0:37.A type MET
135   public ChimeraResidue(String chimeraInputLine)
136   {
137     // initNames();
138     String[] split1 = chimeraInputLine.split(":");
139
140     // First half has model number -- get the number
141     int numberOffset = split1[0].indexOf('#');
142     String model = split1[0].substring(numberOffset + 1);
143     int decimalOffset = model.indexOf('.'); // Do we have a sub-model?
144     try
145     {
146       this.subModelNumber = 0;
147       if (decimalOffset > 0)
148       {
149         this.subModelNumber = Integer
150                 .parseInt(model.substring(decimalOffset + 1));
151         this.modelNumber = Integer
152                 .parseInt(model.substring(0, decimalOffset));
153       }
154       else
155       {
156         this.modelNumber = Integer.parseInt(model);
157       }
158     } catch (Exception e)
159     {
160       LoggerFactory.getLogger(ChimeraResidue.class)
161               .error("Unexpected return from Chimera: " + model);
162       this.modelNumber = -1;
163     }
164
165     // Second half has residue info: index & type
166     String[] rTokens = split1[1].split(" ");
167     this.type = rTokens[2];
168
169     String[] iTokens = rTokens[0].split("\\.");
170     if (iTokens.length > 0)
171     {
172       this.index = iTokens[0];
173
174       // Careful, might or might not have a chainID
175       if (iTokens.length > 1)
176         this.chainId = iTokens[1];
177       else
178         this.chainId = "_";
179     }
180     else
181       this.index = rTokens[0];
182
183     splitInsertionCode(this.index);
184   }
185
186   /**
187    * Set the selected state for this residue
188    * 
189    * @param selected
190    *          the selection state to set
191    */
192   public void setSelected(boolean selected)
193   {
194     this.selected = selected;
195   }
196
197   /**
198    * Return the selected state of this residue
199    * 
200    * @return the selected state
201    */
202   public boolean isSelected()
203   {
204     return selected;
205   }
206
207   /**
208    * Return an array made up of this residue (required for
209    * ChimeraStructuralObject interface
210    * 
211    * @return a List with this residue as its sole member
212    */
213   public List<ChimeraStructuralObject> getChildren()
214   {
215     List<ChimeraStructuralObject> v = new ArrayList<ChimeraStructuralObject>();
216     v.add(this);
217     return v;
218   }
219
220   /**
221    * Return the string representation of this residue as follows:
222    * "<i>residue_name</i> <i>index</i>" where <i>residue_name</i> could be
223    * either the single letter, three letter, or full name representation of the
224    * amino acid.
225    * 
226    * @return the string representation
227    */
228   public String displayName()
229   {
230     return toString();
231   }
232
233   /**
234    * Return the string representation of this residue as follows:
235    * "<i>residue_name</i> <i>index</i>" where <i>residue_name</i> could be
236    * either the single letter, three letter, or full name representation of the
237    * amino acid.
238    * 
239    * @return the string representation
240    */
241   public String toString()
242   {
243     if (displayType == FULL_NAME)
244     {
245       return (ChimUtils.toFullName(type) + " " + index);
246     }
247     else if (displayType == SINGLE_LETTER)
248     {
249       return (ChimUtils.toSingleLetter(type) + " " + index);
250     }
251     else if (displayType == THREE_LETTER)
252     {
253       return (ChimUtils.toThreeLetter(type) + " " + index);
254     }
255     else
256     {
257       return (type + " " + index);
258     }
259   }
260
261   /**
262    * Return the Chimera specification for this Residue
263    * 
264    * @return Chimera specification
265    */
266   public String toSpec()
267   {
268     if (!chainId.equals("_"))
269       return ("#" + modelNumber + ":" + index + "." + chainId);
270     else
271       return ("#" + modelNumber + ":" + index + ".");
272   }
273
274   /**
275    * Get the index of this residue
276    * 
277    * @return residue index
278    */
279   public String getIndex()
280   {
281     return this.index;
282   }
283
284   /**
285    * Get the chainID for this residue
286    * 
287    * @return String value of the chainId
288    */
289   public String getChainId()
290   {
291     return this.chainId;
292   }
293
294   /**
295    * Get the type for this residue
296    * 
297    * @return residue type
298    */
299   public String getType()
300   {
301     return this.type;
302   }
303
304   /**
305    * Get the model number for this residue
306    * 
307    * @return the model number
308    */
309   public int getModelNumber()
310   {
311     return this.modelNumber;
312   }
313
314   /**
315    * Get the sub-model number for this residue
316    * 
317    * @return the sub-model number
318    */
319   public int getSubModelNumber()
320   {
321     return this.subModelNumber;
322   }
323
324   /**
325    * Get the model this residue is part of
326    * 
327    * @return the ChimeraModel
328    */
329   public ChimeraModel getChimeraModel()
330   {
331     return this.chimeraModel;
332   }
333
334   /**
335    * Set the model this residue is part of
336    * 
337    * @param chimeraModel
338    *          the ChimeraModel this model is part of
339    */
340   public void setChimeraModel(ChimeraModel chimeraModel)
341   {
342     this.chimeraModel = chimeraModel;
343   }
344
345   /**
346    * Get the user data for this residue
347    * 
348    * @return user data
349    */
350   public Object getUserData()
351   {
352     return userData;
353   }
354
355   /**
356    * Set the user data for this Residue
357    * 
358    * @param data
359    *          the user data to associate with this residue
360    */
361   public void setUserData(Object data)
362   {
363     this.userData = data;
364   }
365
366   public int compareTo(ChimeraResidue c2)
367   {
368     if (residueNumber < c2.residueNumber)
369       return -1;
370     else if (residueNumber == c2.residueNumber)
371     {
372       if (insertionCode == null && c2.insertionCode == null)
373         return 0;
374       else if (insertionCode == null)
375         return -1;
376       else if (c2.insertionCode == null)
377         return 1;
378       return (insertionCode.compareTo(c2.insertionCode));
379     }
380     return 1;
381   }
382
383   public void splitInsertionCode(String residue)
384   {
385     // OK, split the index into number and insertion code
386     // JBPNote - m.matches() can be true even if there is no resnum - this can
387     // cause NumberFormatExceptions below
388     Pattern p = Pattern.compile("(\\d*)([A-Z]?)");
389     Matcher m = p.matcher(residue);
390     if (m.matches())
391     {
392       this.residueNumber = Integer.parseInt(m.group(1));
393       if (m.groupCount() > 1)
394         this.insertionCode = m.group(2);
395       else
396         this.insertionCode = null;
397     }
398   }
399
400   /**********************************************
401    * Static routines
402    *********************************************/
403
404   /**
405    * Initialize the residue names
406    */
407   // private static void initNames() {
408   // // Create our residue name table
409   // aaNames = new HashMap<String, String>();
410   // aaNames.put("ALA", "A Ala Alanine N[C@@H](C)C(O)=O");
411   // aaNames.put("ARG", "R Arg Arginine N[C@@H](CCCNC(N)=N)C(O)=O");
412   // aaNames.put("ASN", "N Asn Asparagine N[C@@H](CC(N)=O)C(O)=O");
413   // aaNames.put("ASP", "D Asp Aspartic_acid N[C@@H](CC(O)=O)C(O)=O");
414   // aaNames.put("CYS", "C Cys Cysteine N[C@@H](CS)C(O)=O");
415   // aaNames.put("GLN", "Q Gln Glutamine N[C@H](C(O)=O)CCC(N)=O");
416   // aaNames.put("GLU", "E Glu Glumatic_acid N[C@H](C(O)=O)CCC(O)=O");
417   // aaNames.put("GLY", "G Gly Glycine NCC(O)=O");
418   // aaNames.put("HIS", "H His Histidine N[C@@H](CC1=CN=CN1)C(O)=O");
419   // aaNames.put("ILE", "I Ile Isoleucine N[C@]([C@H](C)CC)([H])C(O)=O");
420   // aaNames.put("LEU", "L Leu Leucine N[C@](CC(C)C)([H])C(O)=O");
421   // aaNames.put("LYS", "K Lys Lysine N[C@](CCCCN)([H])C(O)=O");
422   // aaNames.put("DLY", "K Dly D-Lysine NCCCC[C@@H](N)C(O)=O");
423   // aaNames.put("MET", "M Met Methionine N[C@](CCSC)([H])C(O)=O");
424   // aaNames.put("PHE", "F Phe Phenylalanine N[C@](CC1=CC=CC=C1)([H])C(O)=O");
425   // aaNames.put("PRO", "P Pro Proline OC([C@@]1([H])NCCC1)=O");
426   // aaNames.put("SER", "S Ser Serine OC[C@](C(O)=O)([H])N");
427   // aaNames.put("THR", "T Thr Threonine O[C@H](C)[C@](C(O)=O)([H])N");
428   // aaNames.put("TRP",
429   // "W Trp Tryptophan N[C@@]([H])(CC1=CN([H])C2=C1C=CC=C2)C(O)=O");
430   // aaNames.put("TYR", "Y Tyr Tyrosine N[C@@](C(O)=O)([H])CC1=CC=C(O)C=C1");
431   // aaNames.put("VAL", "V Val Valine N[C@@](C(O)=O)([H])C(C)C");
432   // aaNames.put("ASX", "B Asx Aspartic_acid_or_Asparagine");
433   // aaNames.put("GLX", "Z Glx Glutamine_or_Glutamic_acid");
434   // aaNames.put("XAA", "X Xaa Any_or_unknown_amino_acid");
435   // aaNames.put("HOH", "HOH HOH Water [H]O[H]");
436   // }
437
438   /**
439    * Set the display type.
440    * 
441    * @param type
442    *          the display type
443    */
444   public static void setDisplayType(int type)
445   {
446     displayType = type;
447   }
448
449   public static int getDisplayType()
450   {
451     return displayType;
452   }
453
454   public boolean hasSelectedChildren()
455   {
456     return false;
457   }
458 }