001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 * Created on Jun 17, 2010
021 * Author: ap3
022 *
023 */
024
025package org.biojava.nbio.structure;
026
027import java.io.Serializable;
028import java.io.StringWriter;
029
030/** Everything that is needed to uniquely describe a residue position
031 *
032 * @author Andreas Prlic
033 *
034 */
035public class ResidueNumber implements Serializable, Comparable<ResidueNumber>
036{
037
038        private static final long serialVersionUID = 1773011704758536083L;
039        private String chainId;
040        private Character insCode;
041        private Integer seqNum;
042
043        public ResidueNumber() {
044        }
045
046        public ResidueNumber(ResidueNumber o) {
047                this.chainId = o.chainId;
048                this.insCode = o.insCode;
049                this.seqNum = o.seqNum;
050        }
051
052        public ResidueNumber(String chainId, Integer residueNumber, Character insCode) {
053                this.chainId = chainId;
054                this.seqNum = residueNumber;
055                this.insCode = insCode;
056        }
057
058        public String getChainId()
059        {
060                return chainId;
061        }
062        public void setChainId(String chainId)
063        {
064                this.chainId = chainId;
065        }
066        public Character getInsCode()
067        {
068                return insCode;
069        }
070        public void setInsCode(Character insCode)
071        {
072                this.insCode = insCode;
073        }
074        public Integer getSeqNum()
075        {
076                return seqNum;
077        }
078        public void setSeqNum(Integer seqNum)
079        {
080                this.seqNum = seqNum;
081        }
082
083
084
085
086
087        @Override
088        public boolean equals(Object obj) {
089                if (this == obj)
090                        return true;
091                if (obj == null)
092                        return false;
093                if (getClass() != obj.getClass())
094                        return false;
095                ResidueNumber other = (ResidueNumber) obj;
096                if (chainId == null) {
097                        if (other.chainId != null)
098                                return false;
099                } else if (!chainId.equals(other.chainId))
100                        return false;
101                if (insCode == null) {
102                        if (other.insCode != null)
103                                return false;
104                } else if (!insCode.equals(other.insCode))
105                        return false;
106                if (seqNum == null) {
107                        if (other.seqNum != null)
108                                return false;
109                } else if (!seqNum.equals(other.seqNum))
110                        return false;
111
112                return true;
113        }
114
115        @Override
116        public int hashCode() {
117                final int prime = 31;
118                int result = 1;
119                result = prime * result + ((chainId == null) ? 0 : chainId.hashCode());
120                result = prime * result + ((insCode == null) ? 0 : insCode.hashCode());
121                result = prime * result + ((seqNum == null) ? 0 : seqNum.hashCode());
122                return result;
123        }
124
125        /**
126         * @return The residue number and insertion code as a string, eg "74A"
127         * @see java.lang.Object#toString()
128         */
129        @Override
130        public String toString() {
131
132                StringWriter writer = new StringWriter();
133                //         if ( chainId != null){
134                //                 writer.append(chainId);
135                //                 writer.append(":");
136                //         }
137                writer.append(String.valueOf(seqNum));
138                if (  insCode != null && ( insCode != ' '))
139                        writer.append(insCode);
140
141                return writer.toString();
142        }
143
144        /**
145         * @return The chain, number, and insertion code as a string, eg "B  74A" or "A    1 "
146         */
147        public String toPDB() {
148                String insCodeS ;
149                if ( insCode != null)
150                        insCodeS = insCode+"";
151                else insCodeS = " ";
152                return String.format("%s%4d%-2s", chainId, seqNum, insCodeS);
153        }
154
155
156        /** Convert a string representation of a residue number to a residue number object.
157         * The string representation can be a integer followed by a character.
158         *
159         * @param pdb_code
160         * @return a ResidueNumber object, or null if the input was null
161         */
162        public static ResidueNumber fromString(String pdb_code) {
163                if(pdb_code == null)
164                        return null;
165
166                ResidueNumber residueNumber = new ResidueNumber();
167                Integer resNum = null;
168                String icode = null;
169
170                try {
171                        resNum = Integer.parseInt(pdb_code);
172                } catch ( NumberFormatException e){
173                        // there is an insertion code..
174
175                        // Split at any position that's either:
176                        // preceded by a digit and followed by a non-digit, or
177                        // preceded by a non-digit and followed by a digit.
178                        String[] spl = pdb_code.split("(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)");
179                        if ( spl.length == 2){
180                                resNum = Integer.parseInt(spl[0]);
181                                icode = spl[1];
182                        }
183
184                }
185
186                residueNumber.setSeqNum(resNum);
187                if ( icode == null)
188                        residueNumber.setInsCode(null);
189                else if ( icode.length() > 0)
190                        residueNumber.setInsCode(icode.charAt(0));
191                return residueNumber;
192        }
193
194
195        @Override
196        public int compareTo(ResidueNumber other) {
197
198                // chain id
199                if (chainId != null && other.chainId != null) {
200                        if (!chainId.equals(other.chainId)) return chainId.compareTo(other.chainId);
201                }
202                if (chainId != null && other.chainId == null) {
203                        return 1;
204                } else if (chainId == null && other.chainId != null) {
205                        return -1;
206                }
207
208                // sequence number
209                if (seqNum != null && other.seqNum != null) {
210                        if (!seqNum.equals(other.seqNum)) return seqNum.compareTo(other.seqNum);
211                }
212                if (seqNum != null && other.seqNum == null) {
213                        return 1;
214                } else if (seqNum == null && other.seqNum != null) {
215                        return -1;
216                }
217
218                // insertion code
219                if (insCode != null && other.insCode != null) {
220                        if (!insCode.equals(other.insCode)) return insCode.compareTo(other.insCode);
221                }
222                if (insCode != null && other.insCode == null) {
223                        return 1;
224                } else if (insCode == null && other.insCode != null) {
225                        return -1;
226                }
227
228                return 0;
229        }
230
231        public String printFull() {
232                final String chain = chainId==null? "" : chainId;
233                return chain + "_" + toString();
234        }
235
236}