1 //  $Id: mmdb_chain.h $
2 //  =================================================================
3 //
4 //   CCP4 Coordinate Library: support of coordinate-related
5 //   functionality in protein crystallography applications.
6 //
7 //   Copyright (C) Eugene Krissinel 2000-2013.
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 version 3, modified in accordance with the provisions
12 //    of the license to address the requirements of UK law.
13 //
14 //    You should have received a copy of the modified GNU Lesser
15 //    General Public License along with this library. If not, copies
16 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
17 //
18 //    This program is distributed in the hope that it will be useful,
19 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
20 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 //    GNU Lesser General Public License for more details.
22 //
23 //  =================================================================
24 //
25 //    23.12.15   <--  Date of Last Modification.
26 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 //  -----------------------------------------------------------------
28 //
29 //  **** Module  :  MMDB_Chain <implementation>
30 //       ~~~~~~~~~
31 //  **** Project :  MacroMolecular Data Base (MMDB)
32 //       ~~~~~~~~~
33 //  **** Classes :  mmdb::ProModel     ( a virtue of Model           )
34 //       ~~~~~~~~~  mmdb::DBReference  ( DBREF  records               )
35 //             mmdb::ChainContainer ( container of in-chain classes   )
36 //             mmdb::ContainerChain ( chain containered class template)
37 //             mmdb::SeqAdv         ( SEQADV records                  )
38 //             mmdb::SeqRes         ( SEQRES records                  )
39 //             mmdb::ModRes         ( MODRES records                  )
40 //             mmdb::HetRec         ( HET    records                  )
41 //             mmdb::Chain          ( chain class                     )
42 //
43 //  Copyright (C) E. Krissinel 2000-2015
44 //
45 //  =================================================================
46 //
47 
48 #include <string.h>
49 #include <stdlib.h>
50 
51 #include "mmdb_chain.h"
52 #include "mmdb_model.h"
53 #include "mmdb_manager.h"
54 #include "mmdb_cifdefs.h"
55 #include "mmdb_tables.h"
56 
57 namespace mmdb  {
58 
59   //  ==================  ProModel  ======================
60 
MakeStreamFunctions(ProModel)61   MakeStreamFunctions(ProModel)
62 
63   //  ==============  ChainContainer  ====================
64 
65   PContainerClass ChainContainer::MakeContainerClass ( int ClassID )  {
66     switch (ClassID)  {
67       default :
68       case ClassID_Template    : return
69                                    ClassContainer::MakeContainerClass(ClassID);
70       case ClassID_DBReference : return new DBReference ( chain );
71       case ClassID_SeqAdv      : return new SeqAdv      ( chain );
72       case ClassID_ModRes      : return new ModRes      ( chain );
73       case ClassID_Het         : return new HetRec      ( chain );
74     }
75   }
76 
SetChain(PChain Chain_Owner)77   void ChainContainer::SetChain ( PChain Chain_Owner )  {
78   int i;
79     chain = Chain_Owner;
80     for (i=0;i<length;i++)
81       if (Container[i])
82         (void)PContainerChain(Container[i])->SetChain ( chain );
83   }
84 
Get1stChainID()85   cpstr ChainContainer::Get1stChainID()  {
86   int i;
87     i = 0;
88     if (Container)  {
89       while ((i<length-1) && (!Container[i])) i++;
90       if (Container[i])
91             return PContainerChain(Container[i])->chainID;
92       else  return NULL;
93     } else
94       return NULL;
95   }
96 
MoveByChainID(const ChainID chainID,PChainContainer ChainContainer)97   void ChainContainer::MoveByChainID ( const ChainID chainID,
98                                        PChainContainer ChainContainer ) {
99   int i;
100     for (i=0;i<length;i++)
101       if (Container[i])  {
102         if (!strcmp(PContainerChain(Container[i])->chainID,chainID))  {
103           ChainContainer->AddData ( Container[i] );
104           Container[i] = NULL;
105         }
106       }
107   }
108 
109 
MakeStreamFunctions(ChainContainer)110   MakeStreamFunctions(ChainContainer)
111 
112 
113   //  ================  ContainerChain  ===================
114 
115   ContainerChain::ContainerChain() : ContainerClass()  {
116     chain      = NULL;
117     chainID[0] = char(0);
118   }
119 
ContainerChain(PChain Chain_Owner)120   ContainerChain::ContainerChain ( PChain Chain_Owner)
121                 : ContainerClass()  {
122     chain = Chain_Owner;
123     if (chain)  strcpy ( chainID,chain->GetChainID() );
124           else  chainID[0] = char(0);
125   }
126 
SetChain(PChain Chain_Owner)127   void ContainerChain::SetChain ( PChain Chain_Owner )  {
128     chain = Chain_Owner;
129     if (chain)  strcpy ( chainID,chain->GetChainID() );
130           else  strcpy ( chainID,"" );
131   }
132 
MakeStreamFunctions(ContainerChain)133   MakeStreamFunctions(ContainerChain)
134 
135 
136   //  ================  DBReference  ===================
137 
138   DBReference::DBReference() : ContainerChain()  {
139     InitDBReference();
140   }
141 
DBReference(PChain Chain_Owner)142   DBReference::DBReference( PChain Chain_Owner )
143              : ContainerChain(Chain_Owner)  {
144     InitDBReference();
145   }
146 
DBReference(PChain Chain_Owner,cpstr S)147   DBReference::DBReference ( PChain Chain_Owner, cpstr S )
148              : ContainerChain(Chain_Owner)  {
149     InitDBReference();
150     ConvertPDBASCII ( S );
151   }
152 
DBReference(io::RPStream Object)153   DBReference::DBReference ( io::RPStream Object )
154              : ContainerChain(Object)  {
155     InitDBReference();
156   }
157 
~DBReference()158   DBReference::~DBReference() {}
159 
InitDBReference()160   void  DBReference::InitDBReference()  {
161     seqBeg = 0;
162     strcpy ( insBeg     ,"-"            );
163     seqEnd = 0;
164     strcpy ( insEnd     ,"-"            );
165     strcpy ( database   ,"------"       );
166     strcpy ( dbAccession,"--------"     );
167     strcpy ( dbIdCode   ,"------------" );
168     dbseqBeg = 0;
169     strcpy ( dbinsBeg,"-" );
170     dbseqEnd = 0;
171     strcpy ( dbinsEnd,"-" );
172   }
173 
PDBASCIIDump(pstr S,int N)174   void  DBReference::PDBASCIIDump ( pstr S, int N )  {
175   UNUSED_ARGUMENT(N);
176   //  makes the ASCII PDB DBREF line number N
177   //  from the class' data
178     strcpy ( S,"DBREF" );
179     PadSpaces ( S,80 );
180     strcpy_n  ( &(S[7]),chain->GetEntryID(),4 );
181     if (chain->chainID[0])  S[12] = chain->chainID[0];
182     PutIntIns ( &(S[14]),seqBeg,4,insBeg     );
183     PutIntIns ( &(S[20]),seqEnd,4,insEnd     );
184     strcpy_n  ( &(S[26]),database   ,6       );
185     strcpy_n  ( &(S[33]),dbAccession,8       );
186     strcpy_n  ( &(S[42]),dbIdCode   ,12      );
187     PutIntIns ( &(S[55]),dbseqBeg,5,dbinsBeg );
188     PutIntIns ( &(S[62]),dbseqEnd,5,dbinsEnd );
189   }
190 
MakeCIF(mmcif::PData CIF,int N)191   void  DBReference::MakeCIF ( mmcif::PData CIF, int N )  {
192   UNUSED_ARGUMENT(N);
193   mmcif::PLoop Loop1,Loop2;
194   int          RC1,RC2;
195 
196     RC1 = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ,Loop1 );
197     RC2 = CIF->AddLoop ( CIFCAT_STRUCT_REF    ,Loop2 );
198 
199     if ((RC1!=mmcif::CIFRC_Ok) || (RC2!=mmcif::CIFRC_Ok))  {
200       // the category was (re)created, provide tags
201       Loop1->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE            );
202       Loop1->AddLoopTag ( CIFTAG_NDB_CHAIN_ID               );
203       Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_BEG              );
204       Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE );
205       Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_END              );
206       Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE );
207       Loop1->AddLoopTag ( CIFTAG_NDB_DB_ACCESSION           );
208       Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_BEG               );
209       Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE  );
210       Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_END               );
211       Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_END_INS_CODE  );
212       Loop2->AddLoopTag ( CIFTAG_DB_NAME );
213       Loop2->AddLoopTag ( CIFTAG_DB_CODE );
214     }
215 
216     Loop1->AddString  ( chain->GetEntryID(),true );
217     Loop1->AddString  ( chain->chainID     ,true );
218     Loop1->AddInteger ( seqBeg                   );
219     Loop1->AddString  ( insBeg             ,true );
220     Loop1->AddInteger ( seqEnd                   );
221     Loop1->AddString  ( insEnd             ,true );
222     Loop1->AddString  ( dbAccession        ,true );
223     Loop1->AddInteger ( dbseqBeg                 );
224     Loop1->AddString  ( dbinsBeg           ,true );
225     Loop1->AddInteger ( dbseqEnd                 );
226     Loop1->AddString  ( dbinsEnd           ,true );
227 
228     Loop2->AddString  ( database,true );
229     Loop2->AddString  ( dbIdCode,true );
230 
231   }
232 
GetCIF(mmcif::PData CIF,int & n)233   ERROR_CODE DBReference::GetCIF ( mmcif::PData CIF, int & n )  {
234   //  GetCIF(..) must be always run without reference to Chain,
235   //  see CModel::GetCIF(..).
236   mmcif::PLoop   Loop1,Loop2;
237   mmcif::PStruct Struct2;
238   pstr           F;
239   int            RC,ref_id1,ref_id2;
240   CIF_MODE       CIFMode;
241   ERROR_CODE     rc;
242 
243     Loop1 = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ );
244 
245     if (!Loop1)  {
246       n = -1;
247       return Error_EmptyCIF;
248     }
249 
250     if (n>=Loop1->GetLoopLength())  {
251       n = -1;
252       return Error_EmptyCIF;
253     }
254 
255 
256     //  Determine the ChainID first and store it locally. It will
257     // be used by CModel for generating chains and placing the
258     // primary structure data BEFORE reading the coordinate section.
259     CIFMode = CIF_NDB;
260     F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
261     if ((RC) || (!F))  {
262       CIFMode = CIF_PDBX;
263       F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
264     }
265     if ((!RC) && F)  {
266       strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
267       Loop1->DeleteField ( CIFName(TAG_CHAIN_ID,CIFMode),n );
268     } else
269       strcpy ( chainID,"" );
270 
271 
272     rc = CIFGetInteger(seqBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG,CIFMode),n );
273     if (rc==Error_NoData)   return Error_EmptyCIF;
274     if (rc!=Error_NoError)  return rc;
275     CIFGetString ( insBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG_INS_CODE,CIFMode),
276                    n,sizeof(InsCode),pstr(" ") );
277 
278     rc = CIFGetInteger(seqEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END,CIFMode),n );
279     if (rc==Error_NoData)   return Error_EmptyCIF;
280     if (rc!=Error_NoError)  return rc;
281     CIFGetString ( insEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END_INS_CODE,CIFMode),
282                    n,sizeof(InsCode),pstr(" ") );
283     CIFGetString ( dbAccession,Loop1,CIFName(TAG_DB_ACCESSION,CIFMode),
284                    n,sizeof(DBAcCode),pstr("        ") );
285 
286     rc = CIFGetInteger(dbseqBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG,CIFMode),n);
287     if (rc==Error_NoData)   return Error_EmptyCIF;
288     if (rc!=Error_NoError)  return rc;
289     CIFGetString ( dbinsBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG_INS_CODE,CIFMode),
290                    n,sizeof(InsCode),pstr(" ") );
291 
292     rc = CIFGetInteger(dbseqEnd,Loop1,CIFName(TAG_DB_ALIGN_END,CIFMode),n);
293     if (rc==Error_NoData)   return Error_EmptyCIF;
294     if (rc!=Error_NoError)  return rc;
295     CIFGetString ( dbinsEnd,Loop1,CIFName(TAG_DB_ALIGN_END_INS_CODE,CIFMode),
296                    n,sizeof(InsCode),pstr(" ") );
297 
298     Loop2 = CIF->GetLoop ( CIFCAT_STRUCT_REF );
299     if (Loop2)  {
300       CIFGetString ( database,Loop2,CIFTAG_DB_NAME,n,
301                      sizeof(DBName)  ,pstr("      ")       );
302       CIFGetString ( dbIdCode,Loop2,CIFTAG_DB_CODE,n,
303                      sizeof(DBIdCode),pstr("            ") );
304     } else if (CIFMode==CIF_PDBX)  {
305       Struct2 = CIF->GetStructure ( CIFCAT_STRUCT_REF );
306       if (Struct2 &&
307           (!CIFGetInteger(ref_id1,Loop1,CIFTAG_REF_ID,n)) &&
308           (!CIFGetInteger(ref_id2,Struct2,CIFTAG_ID,false)))  {
309         if (ref_id1==ref_id2)  {
310           CIFGetString ( database,Struct2,CIFTAG_DB_NAME,
311                          sizeof(DBName)  ,pstr("      ")      ,false );
312           CIFGetString ( dbIdCode,Struct2,CIFTAG_DB_CODE,
313                          sizeof(DBIdCode),pstr("            "),false );
314         }
315       }
316     }
317 
318     n++;
319 
320     return Error_NoError;
321 
322   }
323 
324 
ConvertPDBASCII(cpstr S)325   ERROR_CODE DBReference::ConvertPDBASCII ( cpstr S )  {
326   IDCode idCode;
327     if (chain->chainID[0])  {
328       if (S[12]!=chain->chainID[0])
329         return Error_WrongChainID;
330     } else if (S[12]!=' ')  {
331       chain->chainID[0] = S[12];
332       chain->chainID[1] = char(0);
333     } else
334       chain->chainID[0] = char(0);
335     strcpy ( idCode,chain->GetEntryID() );
336     if (idCode[0])  {
337       if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
338         return Error_WrongEntryID;
339     } else  {
340       GetString ( idCode,&(S[7]),4 );
341       chain->SetEntryID ( idCode );
342     }
343     GetIntIns  ( seqBeg,insBeg,&(S[14]),4  );
344     GetIntIns  ( seqEnd,insEnd,&(S[20]),4  );
345     strcpy_ncs ( database     ,&(S[26]),6  );
346     strcpy_ncs ( dbAccession  ,&(S[33]),8  );
347     strcpy_ncs ( dbIdCode     ,&(S[42]),12 );
348     GetIntIns  ( dbseqBeg,dbinsBeg,&(S[55]),5 );
349     GetIntIns  ( dbseqEnd,dbinsEnd,&(S[62]),5 );
350     return Error_NoError;
351   }
352 
Copy(PContainerClass DBRef)353   void  DBReference::Copy ( PContainerClass DBRef )  {
354 
355     ContainerChain::Copy ( DBRef );
356 
357     seqBeg   = PDBReference(DBRef)->seqBeg;
358     seqEnd   = PDBReference(DBRef)->seqEnd;
359     dbseqBeg = PDBReference(DBRef)->dbseqBeg;
360     dbseqEnd = PDBReference(DBRef)->dbseqEnd;
361     strcpy ( insBeg     ,PDBReference(DBRef)->insBeg      );
362     strcpy ( insEnd     ,PDBReference(DBRef)->insEnd      );
363     strcpy ( database   ,PDBReference(DBRef)->database    );
364     strcpy ( dbAccession,PDBReference(DBRef)->dbAccession );
365     strcpy ( dbIdCode   ,PDBReference(DBRef)->dbIdCode    );
366     strcpy ( dbinsBeg   ,PDBReference(DBRef)->dbinsBeg    );
367     strcpy ( dbinsEnd   ,PDBReference(DBRef)->dbinsEnd    );
368 
369   }
370 
write(io::RFile f)371   void  DBReference::write ( io::RFile f )  {
372   byte Version=1;
373     f.WriteByte ( &Version  );
374     f.WriteInt  ( &seqBeg   );
375     f.WriteInt  ( &seqEnd   );
376     f.WriteInt  ( &dbseqBeg );
377     f.WriteInt  ( &dbseqEnd );
378     f.WriteTerLine ( insBeg     ,false );
379     f.WriteTerLine ( insEnd     ,false );
380     f.WriteTerLine ( database   ,false );
381     f.WriteTerLine ( dbAccession,false );
382     f.WriteTerLine ( dbIdCode   ,false );
383     f.WriteTerLine ( dbinsBeg   ,false );
384     f.WriteTerLine ( dbinsEnd   ,false );
385   }
386 
read(io::RFile f)387   void  DBReference::read  ( io::RFile f ) {
388   byte Version;
389     f.ReadByte ( &Version  );
390     f.ReadInt  ( &seqBeg   );
391     f.ReadInt  ( &seqEnd   );
392     f.ReadInt  ( &dbseqBeg );
393     f.ReadInt  ( &dbseqEnd );
394     f.ReadTerLine ( insBeg     ,false );
395     f.ReadTerLine ( insEnd     ,false );
396     f.ReadTerLine ( database   ,false );
397     f.ReadTerLine ( dbAccession,false );
398     f.ReadTerLine ( dbIdCode   ,false );
399     f.ReadTerLine ( dbinsBeg   ,false );
400     f.ReadTerLine ( dbinsEnd   ,false );
401   }
402 
MakeStreamFunctions(DBReference)403   MakeStreamFunctions(DBReference)
404 
405 
406 
407   //  ================  SeqAdv  ===================
408 
409   SeqAdv::SeqAdv() : ContainerChain()  {
410     InitSeqAdv();
411   }
412 
SeqAdv(PChain Chain_Owner)413   SeqAdv::SeqAdv ( PChain Chain_Owner )
414          : ContainerChain(Chain_Owner)  {
415     InitSeqAdv();
416   }
417 
SeqAdv(PChain Chain_Owner,cpstr S)418   SeqAdv::SeqAdv ( PChain Chain_Owner, cpstr S )
419          : ContainerChain(Chain_Owner)  {
420     InitSeqAdv();
421     ConvertPDBASCII ( S );
422   }
423 
SeqAdv(io::RPStream Object)424   SeqAdv::SeqAdv ( io::RPStream Object ) : ContainerChain(Object)  {
425     InitSeqAdv();
426   }
427 
~SeqAdv()428   SeqAdv::~SeqAdv()  {
429     if (conflict)  delete[] conflict;
430   }
431 
InitSeqAdv()432   void  SeqAdv::InitSeqAdv()  {
433     strcpy ( resName    ,"---"       );
434     seqNum = 0;
435     strcpy ( insCode    ,"-"         );
436     strcpy ( database   ,"------"    );
437     strcpy ( dbAccession,"---------" );
438     strcpy ( dbRes      ,"---"       );
439     dbSeq = 0;
440     conflict = NULL;
441     CreateCopy ( conflict,pstr(" ") );
442   }
443 
PDBASCIIDump(pstr S,int N)444   void  SeqAdv::PDBASCIIDump ( pstr S, int N )  {
445   UNUSED_ARGUMENT(N);
446   //  makes the ASCII PDB SEQADV line number N
447   //  from the class' data
448     strcpy     ( S,"SEQADV" );
449     PadSpaces  ( S,80 );
450     strcpy_n   ( &(S[7]) ,chain->GetEntryID(),4 );
451     strcpy_n   ( &(S[12]),resName      ,3 );
452     if (chain->chainID[0])  S[16] = chain->chainID[0];
453     PutIntIns  ( &(S[18]),seqNum,4,insCode );
454     strcpy_n   ( &(S[24]),database   ,4    );
455     strcpy_n   ( &(S[29]),dbAccession,9    );
456     strcpy_n   ( &(S[39]),dbRes      ,3    );
457     PutInteger ( &(S[43]),dbSeq      ,5    );
458     strcpy_n   ( &(S[49]),conflict,IMin(strlen(conflict),21) );
459   }
460 
ConvertPDBASCII(cpstr S)461   ERROR_CODE SeqAdv::ConvertPDBASCII ( cpstr S )  {
462   IDCode idCode;
463     if (chain->chainID[0])  {
464       if (S[16]!=chain->chainID[0])
465         return Error_WrongChainID;
466     } else if (S[16]!=' ')  {
467       chain->chainID[0] = S[16];
468       chain->chainID[1] = char(0);
469     } else
470       chain->chainID[0] = char(0);
471     strcpy ( idCode,chain->GetEntryID() );
472     if (idCode[0])  {
473       if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
474         return Error_WrongEntryID;
475     } else  {
476       GetString ( idCode,&(S[7]),4 );
477       chain->SetEntryID ( idCode );
478     }
479     strcpy_ncs ( resName       ,&(S[12]),3 );
480     GetIntIns  ( seqNum,insCode,&(S[18]),4 );
481     strcpy_ncs ( database      ,&(S[24]),4 );
482     strcpy_ncs ( dbAccession   ,&(S[29]),9 );
483     strcpy_ncs ( dbRes         ,&(S[39]),3 );
484     GetInteger ( dbSeq,&(S[43]),5  );
485     CreateCopy ( conflict,&(S[49]) );
486     CutSpaces  ( conflict,SCUTKEY_END );
487     return Error_NoError;
488   }
489 
490 
MakeCIF(mmcif::PData CIF,int N)491   void  SeqAdv::MakeCIF ( mmcif::PData CIF, int N )  {
492   UNUSED_ARGUMENT(N);
493   mmcif::PLoop Loop;
494   int          RC;
495 
496     RC = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ_DIF,Loop );
497 
498     if (RC!=mmcif::CIFRC_Ok)  {
499       // the category was (re)created, provide tags
500       Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE           );
501       Loop->AddLoopTag ( CIFTAG_MON_ID                    );
502       Loop->AddLoopTag ( CIFTAG_NDB_PDB_CHAIN_ID          );
503       Loop->AddLoopTag ( CIFTAG_SEQ_NUM                   );
504       Loop->AddLoopTag ( CIFTAG_NDB_PDB_INS_CODE          );
505       Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_NAME           );
506       Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_ACCESSION_CODE );
507       Loop->AddLoopTag ( CIFTAG_DB_MON_ID                 );
508       Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_SEQ_NUM        );
509       Loop->AddLoopTag ( CIFTAG_DETAILS                   );
510     }
511 
512     Loop->AddString  ( chain->GetEntryID(),true );
513     Loop->AddString  ( resName            ,true );
514     Loop->AddString  ( chain->chainID     ,true );
515     Loop->AddInteger ( seqNum                   );
516     Loop->AddString  ( insCode            ,true );
517     Loop->AddString  ( database           ,true );
518     Loop->AddString  ( dbAccession        ,true );
519     Loop->AddString  ( dbRes              ,true );
520     Loop->AddInteger ( dbSeq                    );
521     Loop->AddString  ( conflict           ,true );
522 
523   }
524 
GetCIF(mmcif::PData CIF,int & n)525   ERROR_CODE SeqAdv::GetCIF ( mmcif::PData CIF, int & n )  {
526   //  GetCIF(..) must be always run without reference to Chain,
527   //  see CModel::GetCIF(..).
528   mmcif::PLoop  Loop;
529   pstr          F;
530   int           RC;
531 
532     Loop = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ_DIF );
533     if (!Loop)  {
534       n = -1;
535       return Error_EmptyCIF;
536     }
537 
538     if (n>=Loop->GetLoopLength())  {
539       n = -1;
540       return Error_EmptyCIF;
541     }
542 
543     //  Determine the ChainID first and store it locally. It will
544     // be used by CModel for generating chains and placing the
545     // primary structure data BEFORE reading the coordinate section.
546 
547     F = Loop->GetString ( CIFTAG_NDB_PDB_CHAIN_ID,n,RC );
548     if ((!RC) && F)  {
549       strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
550       Loop->DeleteField ( CIFTAG_NDB_PDB_CHAIN_ID,n );
551     } else
552       strcpy ( chainID,"" );
553 
554     CIFGetString ( resName,Loop,CIFTAG_MON_ID,n,sizeof(ResName),
555                    pstr("UNK") );
556 
557     CIFGetIntegerD ( seqNum,Loop,CIFTAG_SEQ_NUM );
558 
559     CIFGetString ( insCode,Loop,CIFTAG_NDB_PDB_INS_CODE,
560                    n,sizeof(InsCode),pstr(" ") );
561 
562     CIFGetString ( database,Loop,CIFTAG_NDB_SEQ_DB_NAME,n,
563                    sizeof(DBName),pstr(" ") );
564 
565     CIFGetString ( dbAccession,Loop,CIFTAG_NDB_SEQ_DB_ACCESSION_CODE,
566                    n,sizeof(DBAcCode),pstr(" ") );
567 
568     CIFGetString ( dbRes,Loop,CIFTAG_DB_MON_ID,n,sizeof(ResName),
569                    pstr("   ") );
570 
571     CIFGetIntegerD ( dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM );
572   //  if (CIFGetInteger1(dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM,n))
573   //    dbSeq = MinInt4;
574 
575     F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
576     if ((!RC) && F)  {
577       CreateCopy ( conflict,F );
578       Loop->DeleteField ( CIFTAG_DETAILS,n );
579     } else
580       CreateCopy ( conflict,pstr(" ") );
581 
582     n++;
583 
584     return Error_NoError;
585 
586   }
587 
Copy(PContainerClass SeqAdv)588   void  SeqAdv::Copy ( PContainerClass SeqAdv )  {
589 
590     ContainerClass::Copy ( SeqAdv );
591 
592     seqNum = PSeqAdv(SeqAdv)->seqNum;
593     dbSeq  = PSeqAdv(SeqAdv)->dbSeq;
594     strcpy  ( resName    ,PSeqAdv(SeqAdv)->resName     );
595     strcpy  ( insCode    ,PSeqAdv(SeqAdv)->insCode     );
596     strcpy  ( database   ,PSeqAdv(SeqAdv)->database    );
597     strcpy  ( dbAccession,PSeqAdv(SeqAdv)->dbAccession );
598     strcpy  ( dbRes      ,PSeqAdv(SeqAdv)->dbRes       );
599     CreateCopy ( conflict,PSeqAdv(SeqAdv)->conflict    );
600 
601   }
602 
write(io::RFile f)603   void  SeqAdv::write ( io::RFile f )  {
604   byte Version=1;
605     f.WriteByte    ( &Version );
606     f.WriteInt     ( &seqNum  );
607     f.WriteInt     ( &dbSeq   );
608     f.WriteTerLine ( resName    ,false );
609     f.WriteTerLine ( insCode    ,false );
610     f.WriteTerLine ( database   ,false );
611     f.WriteTerLine ( dbAccession,false );
612     f.WriteTerLine ( dbRes      ,false );
613     f.CreateWrite  ( conflict );
614   }
615 
read(io::RFile f)616   void  SeqAdv::read  ( io::RFile f ) {
617   byte Version;
618     f.ReadByte    ( &Version );
619     f.ReadInt     ( &seqNum  );
620     f.ReadInt     ( &dbSeq   );
621     f.ReadTerLine ( resName    ,false );
622     f.ReadTerLine ( insCode    ,false );
623     f.ReadTerLine ( database   ,false );
624     f.ReadTerLine ( dbAccession,false );
625     f.ReadTerLine ( dbRes      ,false );
626     f.CreateRead  ( conflict );
627   }
628 
MakeStreamFunctions(SeqAdv)629   MakeStreamFunctions(SeqAdv)
630 
631 
632 
633   //  ================  SeqRes  ===================
634 
635   SeqRes::SeqRes() : io::Stream()  {
636     InitSeqRes();
637   }
638 
SeqRes(io::RPStream Object)639   SeqRes::SeqRes ( io::RPStream Object ) : io::Stream(Object)  {
640     InitSeqRes();
641   }
642 
~SeqRes()643   SeqRes::~SeqRes()  {
644     FreeMemory();
645   }
646 
SetChain(PChain Chain_Owner)647   void  SeqRes::SetChain ( PChain Chain_Owner )  {
648     chain = Chain_Owner;
649     if (chain)  strcpy ( chainID,chain->chainID );
650           else  strcpy ( chainID,"" );
651   }
652 
InitSeqRes()653   void  SeqRes::InitSeqRes()  {
654     chain   = NULL;
655     numRes  = -1;
656     resName = NULL;
657     serNum  = 0;
658     strcpy ( chainID,"" );
659   }
660 
FreeMemory()661   void  SeqRes::FreeMemory()  {
662     if (resName)  delete[] resName;
663     resName = NULL;
664     numRes  = -1;
665     serNum  = 0;
666   }
667 
PDBASCIIDump(io::RFile f)668   void  SeqRes::PDBASCIIDump ( io::RFile f )  {
669   //  writes the ASCII PDB SEQRES lines into file f
670   char S[100];
671   int  i,k,sN;
672     if (numRes<0)  return;
673     strcpy     ( S,"SEQRES" );
674     PadSpaces  ( S,80 );
675     if (chain->chainID[0])
676       S[11] = chain->chainID[0];
677     PutInteger ( &(S[13]),numRes,4 );
678     if (resName)  {
679       i  = 0;
680       sN = 1;
681       while (i<numRes)  {
682         PutInteger ( &(S[7]),sN,3 );
683         k = 19;
684         while ((i<numRes) && (k<70))  {
685           if (resName[i][0])
686                 strcpy_n ( &(S[k]),resName[i],3 );
687           else  strcpy_n ( &(S[k]),pstr("   "),3 );
688           i++;
689           k += 4;
690         }
691         while (k<70)  {
692           strcpy_n ( &(S[k]),pstr("   "),3 );
693           k += 4;
694         }
695         f.WriteLine ( S );
696         sN++;
697       }
698     } else  {
699       S[9] = '0';
700       strcpy_n ( &(S[19]),pstr("UNK"),3 );
701       f.WriteLine ( S );
702     }
703   }
704 
ConvertPDBASCII(cpstr S)705   ERROR_CODE SeqRes::ConvertPDBASCII ( cpstr S )  {
706   int i,k,sN,nR;
707     if (chain->chainID[0])  {
708       if (S[11]!=chain->chainID[0])
709         return Error_WrongChainID;
710     } else if (S[11]!=' ')  {
711       chain->chainID[0] = S[11];
712       chain->chainID[1] = char(0);
713     } else
714       chain->chainID[0] = char(0);
715     GetInteger ( sN,&(S[8]) ,3 );
716     GetInteger ( nR,&(S[13]),4 );
717     if (sN==0)  {
718       FreeMemory();
719       numRes = nR;
720     } else  {
721       serNum++;
722       if (sN!=serNum)
723         return Error_SEQRES_serNum;
724       if (sN==1)  {
725         FreeMemory();
726         resName = new ResName[nR];
727         for (i=0;i<nR;i++)
728           resName[i][0] = char(0);
729         numRes  = nR;
730         serNum  = sN;
731       } else if (nR!=numRes)
732         return Error_SEQRES_numRes;
733       i = 0;
734       while ((i<nR) && (resName[i][0]))  i++;
735       if (i>=nR)
736         return Error_SEQRES_extraRes;
737       k = 19;
738       while ((i<nR) && (k<70))  {
739         GetString ( resName[i],&(S[k]),3 );
740         if (!strcmp(resName[i],"   "))  resName[i][0] = char(0);
741                                   else  i++;
742         k += 4;
743       }
744     }
745     return Error_NoError;
746   }
747 
748 
MakeCIF(mmcif::PData CIF)749   void  SeqRes::MakeCIF ( mmcif::PData CIF )  {
750   //  Note that SeqRes only adds sequence to the CIF loop common
751   // to all chains. Therefore this loop should be wiped off from
752   // CIF structure before putting first sequence into it.
753   mmcif::PLoop Loop;
754   int          RC,i;
755 
756     if (numRes<0)  return;
757 
758     RC = CIF->AddLoop ( CIFCAT_NDB_POLY_SEQ_SCHEME,Loop );
759     if (RC!=mmcif::CIFRC_Ok)  {
760       // the category was (re)created, provide tags
761       Loop->AddLoopTag ( CIFTAG_ID     );
762       Loop->AddLoopTag ( CIFTAG_MON_ID );
763     }
764 
765     if (resName)
766       for (i=0;i<numRes;i++)  {
767         Loop->AddString  ( chain->chainID,true );
768         Loop->AddString  ( resName[i]    ,true );
769       }
770     else
771       for (i=0;i<numRes;i++)  {
772         Loop->AddString  ( chain->GetEntryID(),true );
773         Loop->AddString  ( pstr("UNK")        ,true );
774       }
775 
776   }
777 
GetCIF(mmcif::PData CIF)778   ERROR_CODE SeqRes::GetCIF ( mmcif::PData CIF )  {
779   //   Tries to get sequence from the CIF structure. A sequence
780   // for first met chain is extracted and then removed from
781   // the CIF structure, so that sequential calls will extract
782   // all sequencies. Chain ID is stored locally in chainID;
783   // reference to parent chain is neither used nor checked.
784   //   Returns 0 if sequence was extracted and 1 otherwise.
785   mmcif::PLoop Loop;
786   ResName    * rN;
787   ChainID      chID;
788   pstr         F;
789   cpstr        CHAIN_ID;
790   int          RC,i,l;
791   CIF_MODE     CIFMode;
792   bool         isMon;
793 
794     FreeMemory();
795 
796     CIFMode = CIF_NDB;
797     Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
798     if (!Loop)  {
799       CIFMode = CIF_PDBX;
800       Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
801       if (!Loop)  return Error_NoLoop;
802     }
803 
804     l = Loop->GetLoopLength();
805     if (l<=0)  return Error_NoLoop;
806 
807     rN         = new ResName[l];
808     chainID[0] = char(1);
809     numRes     = 0;
810     isMon      = false;
811     CHAIN_ID   = CIFName(TAG_SEQ_CHAIN_ID,CIFMode);
812     for (i=0;i<l;i++)  {
813       F = Loop->GetString ( CHAIN_ID,i,RC );
814       if (!RC)  {
815         if (F)  strcpy ( chID,F );
816           else  chID[0] = char(0);
817         if (chainID[0]==char(1))  strcpy ( chainID,chID );
818         if (!strcmp(chainID,chID))  {
819           CIFGetString ( rN[numRes],Loop,CIFTAG_MON_ID,i,
820                          sizeof(ResName),pstr("UNK") );
821           Loop->DeleteField ( CHAIN_ID,i );
822           if (strcmp(rN[numRes],"UNK")) isMon = true;
823           numRes++;
824         }
825       }
826     }
827 
828     if (numRes==0)  {
829       numRes = -1;
830       delete[] rN;
831       return Error_EmptyCIFLoop;
832     }
833 
834     if (isMon)  {
835       resName = new ResName[numRes];
836       for (i=0;i<numRes;i++)
837         strcpy ( resName[i],rN[i] );
838     }
839 
840     delete[] rN;
841 
842     return Error_NoError;
843 
844   }
845 
Copy(PSeqRes SeqRes)846   void  SeqRes::Copy ( PSeqRes SeqRes )  {
847   int i;
848 
849     FreeMemory();
850 
851     numRes = SeqRes->numRes;
852     serNum = SeqRes->serNum;
853 
854     if (SeqRes->resName)  {
855       resName = new ResName[numRes];
856       for (i=0;i<numRes;i++)
857         strcpy ( resName[i],SeqRes->resName[i] );
858     }
859 
860   }
861 
write(io::RFile f)862   void  SeqRes::write ( io::RFile f )  {
863   int  i;
864   byte Version=1;
865     f.WriteByte ( &Version );
866     f.WriteInt  ( &numRes  );
867     f.WriteInt  ( &serNum  );
868     if (resName)  i = 1;
869             else  i = 0;
870     f.WriteInt ( &i );
871     if (resName)
872       for (i=0;i<numRes;i++)
873         f.WriteTerLine ( resName[i],false );
874   }
875 
read(io::RFile f)876   void  SeqRes::read  ( io::RFile f ) {
877   int  i;
878   byte Version;
879     FreeMemory();
880     f.ReadByte ( &Version );
881     f.ReadInt  ( &numRes  );
882     f.ReadInt  ( &serNum  );
883     f.ReadInt  ( &i       );
884     if (i)  {
885       resName = new ResName[numRes];
886       for (i=0;i<numRes;i++)
887         f.ReadTerLine ( resName[i],false );
888     }
889   }
890 
891 
MakeStreamFunctions(SeqRes)892   MakeStreamFunctions(SeqRes)
893 
894 
895 
896   //  ================  ModRes  ===================
897 
898   ModRes::ModRes() : ContainerChain()  {
899     InitModRes();
900   }
901 
ModRes(PChain Chain_Owner)902   ModRes::ModRes ( PChain Chain_Owner )
903         : ContainerChain(Chain_Owner)  {
904     InitModRes();
905   }
906 
ModRes(PChain Chain_Owner,cpstr S)907   ModRes::ModRes ( PChain Chain_Owner, cpstr S )
908         : ContainerChain(Chain_Owner)  {
909     InitModRes();
910     ConvertPDBASCII ( S );
911   }
912 
ModRes(io::RPStream Object)913   ModRes::ModRes ( io::RPStream Object ) : ContainerChain(Object)  {
914     InitModRes();
915   }
916 
~ModRes()917   ModRes::~ModRes()  {
918     if (comment)  delete[] comment;
919   }
920 
InitModRes()921   void  ModRes::InitModRes()  {
922     strcpy     ( resName,"---" );
923     seqNum  = 0;
924     strcpy     ( insCode,"-"   );
925     comment = NULL;
926     CreateCopy ( comment,pstr(" ") );
927     strcpy     ( stdRes ,"---" );
928   }
929 
PDBASCIIDump(pstr S,int N)930   void  ModRes::PDBASCIIDump ( pstr S, int N )  {
931   UNUSED_ARGUMENT(N);
932   //  makes the ASCII PDB MODRES line number N
933   //  from the class' data
934     strcpy     ( S,"MODRES" );
935     PadSpaces  ( S,80 );
936     strcpy_n   ( &(S[7]) ,chain->GetEntryID(),4  );
937     strcpy_n   ( &(S[12]),resName      ,3  );
938     if (chain->chainID[0])  S[16] = chain->chainID[0];
939     PutIntIns  ( &(S[18]),seqNum,4,insCode );
940     strcpy_n   ( &(S[24]),stdRes       ,3  );
941     strcpy_n   ( &(S[29]),comment,IMin(strlen(comment),41) );
942   }
943 
ConvertPDBASCII(cpstr S)944   ERROR_CODE ModRes::ConvertPDBASCII ( cpstr S )  {
945   IDCode idCode;
946     if (chain->chainID[0])  {
947       if (S[16]!=chain->chainID[0])
948         return Error_WrongChainID;
949     } else if (S[16]!=' ')  {
950       chain->chainID[0] = S[16];
951       chain->chainID[1] = char(0);
952     } else
953       chain->chainID[0] = char(0);
954     strcpy ( idCode,chain->GetEntryID() );
955     if (idCode[0])  {
956       if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
957         return Error_WrongEntryID;
958     } else  {
959       GetString ( idCode,&(S[7]),4 );
960       chain->SetEntryID ( idCode );
961     }
962     GetString  ( resName       ,&(S[12]),3 );
963     GetIntIns  ( seqNum,insCode,&(S[18]),4 );
964     GetString  ( stdRes        ,&(S[24]),3 );
965     CreateCopy ( comment       ,&(S[29])   );
966     CutSpaces  ( comment,SCUTKEY_END       );
967     return Error_NoError;
968   }
969 
MakeCIF(mmcif::PData CIF,int N)970   void  ModRes::MakeCIF ( mmcif::PData CIF, int N )  {
971   UNUSED_ARGUMENT(CIF);
972   UNUSED_ARGUMENT(N);
973   /*  -- apparently wrong use of _struct_conn, to be revised
974   mmcif::PLoop Loop;
975   int         RC;
976 
977     RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
978 
979     if (RC!=mmcif::CIFRC_Ok)  {
980       // the category was (re)created, provide tags
981       Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID               );
982       Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID                 );
983       Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_COMP_ID        );
984       Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_ASYM_ID        );
985       Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_SEQ_ID         );
986       Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_LABEL_INS_CODE   );
987       Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_STANDARD_COMP_ID );
988       Loop->AddLoopTag ( CIFTAG_DETAILS                    );
989     }
990 
991     Loop->AddString  ( pstr("MODRES")           );
992     Loop->AddString  ( chain->GetEntryID(),true );
993     Loop->AddString  ( resName            ,true );
994     Loop->AddString  ( chain->chainID     ,true );
995     Loop->AddInteger ( seqNum                   );
996     Loop->AddString  ( insCode            ,true );
997     Loop->AddString  ( stdRes             ,true );
998     Loop->AddString  ( comment            ,true );
999 
1000   */
1001 
1002   }
1003 
GetCIF(mmcif::PData CIF,int & n)1004   ERROR_CODE ModRes::GetCIF ( mmcif::PData CIF, int & n )  {
1005   UNUSED_ARGUMENT(CIF);
1006   //  GetCIF(..) must be always run without reference to Chain,
1007   //  see CModel::GetCIF(..).
1008 
1009   /*  -- apparently wrong use of _struct_conn, to be revised
1010   mmcif::PLoop   Loop;
1011   pstr          F;
1012   int           l,RC;
1013 
1014     Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
1015     if (!Loop)  {
1016       n = -1;
1017       return;
1018     }
1019 
1020     l = Loop->GetLoopLength();
1021     while (n<l)  {
1022       F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
1023       if ((!RC) && F)  {
1024         if (!strcmp(F,"MODRES"))  break;
1025       }
1026       n++;
1027     }
1028     if (n>=l)  {
1029       n = -1;
1030       return;
1031     }
1032 
1033     Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
1034 
1035     //  Determine the ChainID first and store it locally. It will
1036     // be used by CModel for generating chains and placing the
1037     // primary structure data BEFORE reading the coordinate section.
1038     F = Loop->GetString ( CIFTAG_PTNR1_LABEL_ASYM_ID,n,RC );
1039     if ((!RC) && F)  {
1040       strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
1041       Loop->DeleteField ( CIFTAG_PTNR1_LABEL_ASYM_ID,n );
1042     } else
1043       strcpy ( chainID,"" );
1044 
1045 
1046     CIFGetString ( resName,Loop,CIFTAG_PTNR1_LABEL_COMP_ID,n,
1047                    sizeof(ResName),pstr("UNK") );
1048 
1049     if (CIFGetInteger(seqNum,Loop,CIFTAG_PTNR1_LABEL_SEQ_ID,n))
1050       return;
1051 
1052     CIFGetString ( insCode,Loop,CIFTAG_NDB_PTNR1_LABEL_INS_CODE,
1053                    n,sizeof(InsCode),pstr(" ") );
1054 
1055     CIFGetString ( stdRes,Loop,CIFTAG_NDB_PTNR1_STANDARD_COMP_ID,n,
1056                    sizeof(ResName),pstr("UNK") );
1057 
1058     F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
1059     if ((!RC) && F)  {
1060       CreateCopy ( comment,F );
1061       Loop->DeleteField ( CIFTAG_DETAILS,n );
1062     } else
1063       CreateCopy ( comment,pstr(" ") );
1064 
1065     n++;
1066 
1067   */
1068 
1069     n = -1;
1070 
1071     return Error_EmptyCIF;
1072 
1073   }
1074 
Copy(PContainerClass ModRes)1075   void  ModRes::Copy ( PContainerClass ModRes )  {
1076     seqNum = PModRes(ModRes)->seqNum;
1077     strcpy ( resName,PModRes(ModRes)->resName );
1078     strcpy ( insCode,PModRes(ModRes)->insCode );
1079     strcpy ( stdRes ,PModRes(ModRes)->stdRes  );
1080     CreateCopy ( comment,PModRes(ModRes)->comment );
1081   }
1082 
write(io::RFile f)1083   void  ModRes::write ( io::RFile f )  {
1084   byte Version=1;
1085     f.WriteByte    ( &Version );
1086     f.WriteInt     ( &seqNum  );
1087     f.WriteTerLine ( resName,false );
1088     f.WriteTerLine ( insCode,false );
1089     f.WriteTerLine ( stdRes ,false );
1090     f.CreateWrite  ( comment  );
1091   }
1092 
read(io::RFile f)1093   void  ModRes::read  ( io::RFile f ) {
1094   byte Version;
1095     f.ReadByte    ( &Version );
1096     f.ReadInt     ( &seqNum  );
1097     f.ReadTerLine ( resName,false );
1098     f.ReadTerLine ( insCode,false );
1099     f.ReadTerLine ( stdRes ,false );
1100     f.CreateRead  ( comment  );
1101   }
1102 
MakeStreamFunctions(ModRes)1103   MakeStreamFunctions(ModRes)
1104 
1105 
1106 
1107   //  ================  HetRec  ======================
1108 
1109   HetRec::HetRec() : ContainerChain()  {
1110     InitHetRec();
1111   }
1112 
HetRec(PChain Chain_Owner)1113   HetRec::HetRec ( PChain Chain_Owner )
1114         : ContainerChain(Chain_Owner)  {
1115     InitHetRec();
1116   }
1117 
HetRec(PChain Chain_Owner,cpstr S)1118   HetRec::HetRec ( PChain Chain_Owner, cpstr S )
1119         : ContainerChain(Chain_Owner)  {
1120     InitHetRec();
1121     ConvertPDBASCII ( S );
1122   }
1123 
HetRec(io::RPStream Object)1124   HetRec::HetRec ( io::RPStream Object ) : ContainerChain(Object)  {
1125     InitHetRec();
1126   }
1127 
~HetRec()1128   HetRec::~HetRec()  {
1129     if (comment)  delete[] comment;
1130   }
1131 
InitHetRec()1132   void  HetRec::InitHetRec()  {
1133     strcpy ( hetID  ,"---" );
1134     strcpy ( insCode,"-"   );
1135     seqNum      = 0;
1136     numHetAtoms = 0;
1137     comment     = NULL;
1138     CreateCopy ( comment,pstr(" ") );
1139   }
1140 
PDBASCIIDump(pstr S,int N)1141   void  HetRec::PDBASCIIDump ( pstr S, int N )  {
1142   UNUSED_ARGUMENT(N);
1143   //  makes the ASCII PDB MODRES line number N
1144   //  from the class' data
1145     strcpy     ( S,"HET" );
1146     PadSpaces  ( S,80 );
1147     strcpy_n   ( &(S[7]) ,hetID,3  );
1148     if (chain->chainID[0])  S[12] = chain->chainID[0];
1149     PutIntIns  ( &(S[13]),seqNum,4,insCode );
1150     PutInteger ( &(S[20]),numHetAtoms,5    );
1151     strcpy_n   ( &(S[30]),comment,IMin(strlen(comment),40) );
1152   }
1153 
ConvertPDBASCII(cpstr S)1154   ERROR_CODE HetRec::ConvertPDBASCII ( cpstr S )  {
1155     if (chain->chainID[0])  {
1156       if (S[12]!=chain->chainID[0])
1157         return Error_WrongChainID;
1158     } else if (S[12]!=' ')  {
1159       chain->chainID[0] = S[12];
1160       chain->chainID[1] = char(0);
1161     } else
1162       chain->chainID[0] = char(0);
1163     GetString  ( hetID         ,&(S[7]) ,3 );
1164     GetIntIns  ( seqNum,insCode,&(S[13]),4 );
1165     GetInteger ( numHetAtoms   ,&(S[20]),5 );
1166     CreateCopy ( comment       ,&(S[30])   );
1167     CutSpaces  ( comment,SCUTKEY_END       );
1168     return Error_NoError;
1169   }
1170 
MakeCIF(mmcif::PData CIF,int N)1171   void  HetRec::MakeCIF ( mmcif::PData CIF, int N )  {
1172   UNUSED_ARGUMENT(N);
1173   mmcif::PLoop Loop;
1174   int         RC;
1175 
1176     RC = CIF->AddLoop ( CIFCAT_NDB_NONSTANDARD_LIST,Loop );
1177 
1178     if (RC!=mmcif::CIFRC_Ok)  {
1179       // the category was (re)created, provide tags
1180       Loop->AddLoopTag ( CIFTAG_ID              );
1181       Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID    );
1182       Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID     );
1183       Loop->AddLoopTag ( CIFTAG_INS_CODE        );
1184       Loop->AddLoopTag ( CIFTAG_NUMBER_ATOMS_NH );
1185       Loop->AddLoopTag ( CIFTAG_DETAILS         );
1186     }
1187 
1188     Loop->AddString  ( hetID         ,true );
1189     Loop->AddString  ( chain->chainID,true );
1190     Loop->AddInteger ( seqNum              );
1191     Loop->AddString  ( insCode       ,true );
1192     Loop->AddInteger ( numHetAtoms         );
1193     Loop->AddString  ( comment       ,true );
1194 
1195   }
1196 
GetCIF(mmcif::PData CIF,int & n)1197   ERROR_CODE HetRec::GetCIF ( mmcif::PData CIF, int & n )  {
1198   //  GetCIF(..) must be always run without reference to Chain,
1199   //  see CModel::GetCIF(..).
1200   mmcif::PLoop   Loop;
1201   pstr           F;
1202   int            RC;
1203   ERROR_CODE     rc;
1204 
1205     Loop = CIF->GetLoop ( CIFCAT_NDB_NONSTANDARD_LIST );
1206     if (!Loop)  {
1207       n = -1;
1208       return Error_EmptyCIF;
1209     }
1210 
1211     if (n>=Loop->GetLoopLength())  {
1212       n = -1;
1213       return Error_EmptyCIF;
1214     }
1215 
1216     //  Determine the ChainID first and store it locally. It will
1217     // be used by CModel for generating chains and placing the
1218     // primary structure data BEFORE reading the coordinate section.
1219     F = Loop->GetString ( CIFTAG_AUTH_ASYM_ID,n,RC );
1220     if ((!RC) && F)  {
1221       strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
1222       Loop->DeleteField ( CIFTAG_AUTH_ASYM_ID,n );
1223     } else
1224       strcpy ( chainID,"" );
1225 
1226 
1227     CIFGetString ( hetID,Loop,CIFTAG_ID,n,sizeof(ResName),
1228                    pstr("UNK") );
1229 
1230     rc = CIFGetInteger ( seqNum,Loop,CIFTAG_AUTH_SEQ_ID,n );
1231     if (rc==Error_NoData)   return Error_EmptyCIF;
1232     if (rc!=Error_NoError)  return rc;
1233 
1234     CIFGetString ( insCode,Loop,CIFTAG_INS_CODE,n,sizeof(InsCode),
1235                    pstr(" ") );
1236 
1237     rc = CIFGetInteger ( numHetAtoms,Loop,CIFTAG_NUMBER_ATOMS_NH,n );
1238     if (rc==Error_NoData)   return Error_EmptyCIF;
1239     if (rc!=Error_NoError)  return rc;
1240 
1241     F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
1242     if ((!RC) && F)  {
1243       CreateCopy ( comment,F );
1244       Loop->DeleteField ( CIFTAG_DETAILS,n );
1245     } else
1246       CreateCopy ( comment,pstr(" ") );
1247 
1248     n++;
1249 
1250     return Error_NoError;
1251 
1252   }
1253 
Copy(PContainerClass Het)1254   void  HetRec::Copy ( PContainerClass Het )  {
1255     seqNum      = PHetRec(Het)->seqNum;
1256     numHetAtoms = PHetRec(Het)->numHetAtoms;
1257     strcpy     ( hetID  ,PHetRec(Het)->hetID   );
1258     strcpy     ( insCode,PHetRec(Het)->insCode );
1259     CreateCopy ( comment,PHetRec(Het)->comment );
1260   }
1261 
write(io::RFile f)1262   void  HetRec::write ( io::RFile f )  {
1263   byte Version=1;
1264     f.WriteByte    ( &Version      );
1265     f.WriteInt     ( &seqNum       );
1266     f.WriteInt     ( &numHetAtoms  );
1267     f.WriteTerLine ( hetID  ,false );
1268     f.WriteTerLine ( insCode,false );
1269     f.CreateWrite  ( comment       );
1270   }
1271 
read(io::RFile f)1272   void  HetRec::read  ( io::RFile f ) {
1273   byte Version;
1274     f.ReadByte    ( &Version      );
1275     f.ReadInt     ( &seqNum       );
1276     f.ReadInt     ( &numHetAtoms  );
1277     f.ReadTerLine ( hetID  ,false );
1278     f.ReadTerLine ( insCode,false );
1279     f.CreateRead  ( comment       );
1280   }
1281 
MakeStreamFunctions(HetRec)1282   MakeStreamFunctions(HetRec)
1283 
1284 
1285 
1286   //  =====================   Chain   =======================
1287 
1288   Chain::Chain() : UDData() {
1289     InitChain();
1290     SetChain ( pstr("") );
1291   }
1292 
Chain(PProModel Model,const ChainID chID)1293   Chain::Chain ( PProModel Model, const ChainID chID ) : UDData()  {
1294     InitChain();
1295     SetChain ( chID );
1296     if (Model)  Model->AddChain ( this );
1297   }
1298 
Chain(io::RPStream Object)1299   Chain::Chain ( io::RPStream Object ) : UDData(Object)  {
1300     InitChain();
1301     SetChain ( pstr("") );
1302   }
1303 
InitChain()1304   void  Chain::InitChain()  {
1305     nResidues      = 0;
1306     resLen         = 0;
1307     residue        = NULL;
1308     model          = NULL;
1309     chainID[0]     = char(0);
1310     prevChainID[0] = char(0);
1311     nWeights       = 0;
1312     Weight         = 0.0;
1313     Exclude        = true;
1314   }
1315 
SetChain(const ChainID chID)1316   void  Chain::SetChain ( const ChainID chID )  {
1317     strcpy ( chainID,chID );
1318     if (chID[0]==' ')  chainID[0] = char(0);
1319     DBRef .SetChain ( this );
1320     seqAdv.SetChain ( this );
1321     seqRes.SetChain ( this );
1322     modRes.SetChain ( this );
1323     Het   .SetChain ( this );
1324   }
1325 
SetChainID(const ChainID chID)1326   void  Chain::SetChainID ( const ChainID chID )  {
1327     strcpy ( chainID,chID );
1328     if (chID[0]==' ')  chainID[0] = char(0);
1329   }
1330 
~Chain()1331   Chain::~Chain()  {
1332     FreeMemory();
1333     if (model)  model->_ExcludeChain ( chainID );
1334   }
1335 
FreeMemory()1336   void  Chain::FreeMemory()  {
1337     DeleteAllResidues();
1338     if (residue)  delete[] residue;
1339     resLen    = 0;
1340     nResidues = 0;
1341     residue   = NULL;
1342     FreeAnnotations();
1343   }
1344 
FreeAnnotations()1345   void  Chain::FreeAnnotations()  {
1346     DBRef .FreeContainer();
1347     seqAdv.FreeContainer();
1348     seqRes.FreeMemory   ();
1349     modRes.FreeContainer();
1350     Het   .FreeContainer();
1351   }
1352 
SetModel(PProModel Model)1353   void Chain::SetModel ( PProModel Model )  {
1354     model = Model;
1355   }
1356 
GetCoordHierarchy()1357   PManager Chain::GetCoordHierarchy()  {
1358     if (model)  return model->GetCoordHierarchy();
1359     return NULL;
1360   }
1361 
CheckInAtoms()1362   void Chain::CheckInAtoms()  {
1363   int i;
1364     if (GetCoordHierarchy())
1365       for (i=0;i<nResidues;i++)
1366         if (residue[i])
1367           residue[i]->CheckInAtoms();
1368   }
1369 
ConvertDBREF(cpstr PDBString)1370   ERROR_CODE Chain::ConvertDBREF ( cpstr PDBString ) {
1371   PContainerChain ContainerChain;
1372   ERROR_CODE      RC;
1373     ContainerChain = new DBReference(this);
1374     RC = ContainerChain->ConvertPDBASCII ( PDBString );
1375     if (RC)  {
1376       delete ContainerChain;
1377       return RC;
1378     }
1379     DBRef.AddData ( ContainerChain );
1380     return Error_NoError;
1381   }
1382 
ConvertSEQADV(cpstr PDBString)1383   ERROR_CODE Chain::ConvertSEQADV ( cpstr PDBString ) {
1384   PContainerChain ContainerChain;
1385   ERROR_CODE      RC;
1386     ContainerChain = new SeqAdv(this);
1387     RC = ContainerChain->ConvertPDBASCII ( PDBString );
1388     if (RC)  {
1389       delete ContainerChain;
1390       return RC;
1391     }
1392     seqAdv.AddData ( ContainerChain );
1393     return Error_NoError;
1394   }
1395 
ConvertSEQRES(cpstr PDBString)1396   ERROR_CODE Chain::ConvertSEQRES ( cpstr PDBString ) {
1397     return seqRes.ConvertPDBASCII ( PDBString );
1398   }
1399 
ConvertMODRES(cpstr PDBString)1400   ERROR_CODE Chain::ConvertMODRES ( cpstr PDBString ) {
1401   PContainerChain ContainerChain;
1402   ERROR_CODE      RC;
1403     ContainerChain = new ModRes(this);
1404     RC = ContainerChain->ConvertPDBASCII ( PDBString );
1405     if (RC)  {
1406       delete ContainerChain;
1407       return RC;
1408     }
1409     modRes.AddData ( ContainerChain );
1410     return Error_NoError;
1411   }
1412 
ConvertHET(cpstr PDBString)1413   ERROR_CODE  Chain::ConvertHET ( cpstr PDBString ) {
1414   PContainerChain ContainerChain;
1415   ERROR_CODE      RC;
1416     ContainerChain = new HetRec(this);
1417     RC = ContainerChain->ConvertPDBASCII ( PDBString );
1418     if (RC)  {
1419       delete ContainerChain;
1420       return RC;
1421     }
1422     Het.AddData ( ContainerChain );
1423     return Error_NoError;
1424   }
1425 
1426 
PDBASCIIDump(io::RFile f)1427   void  Chain::PDBASCIIDump ( io::RFile f )  {
1428   // this function was for test purposes and is not used
1429   // for normal function of MMDB
1430     DBRef .PDBASCIIDump ( f );
1431     seqAdv.PDBASCIIDump ( f );
1432     seqRes.PDBASCIIDump ( f );
1433     modRes.PDBASCIIDump ( f );
1434     Het   .PDBASCIIDump ( f );
1435   }
1436 
PDBASCIIAtomDump(io::RFile f)1437   void  Chain::PDBASCIIAtomDump ( io::RFile f )  {
1438   int i;
1439     for (i=0;i<nResidues;i++)
1440       if (residue[i])
1441         residue[i]->PDBASCIIAtomDump ( f );
1442   }
1443 
MakeAtomCIF(mmcif::PData CIF)1444   void  Chain::MakeAtomCIF ( mmcif::PData CIF )  {
1445   int i;
1446     for (i=0;i<nResidues;i++)
1447       if (residue[i])
1448         residue[i]->MakeAtomCIF ( CIF );
1449   }
1450 
1451 
GetNumberOfResidues()1452   int  Chain::GetNumberOfResidues()  {
1453     return nResidues;
1454   }
1455 
GetResidue(int resNo)1456   PResidue Chain::GetResidue ( int resNo )  {
1457     if ((0<=resNo) && (resNo<nResidues))
1458           return residue[resNo];
1459     else  return NULL;
1460   }
1461 
1462 
GetResidueCreate(const ResName resName,int seqNum,const InsCode insCode,bool Enforce)1463   PResidue Chain::GetResidueCreate ( const ResName resName,
1464                                      int           seqNum,
1465                                      const InsCode insCode,
1466                                      bool          Enforce )  {
1467   //   Returns pointer on residue, whose name, sequence number and
1468   // insert code are given in resName, seqNum and insCode, respectively.
1469   // If such a residue is absent in the chain, one is created at
1470   // the end of the chain.
1471   int i;
1472 
1473     // check if such a residue is already in the chain
1474     if (insCode[0])  {
1475       for (i=0;i<nResidues;i++)
1476         if (residue[i])  {
1477           if ((seqNum==residue[i]->seqNum) &&
1478               (!strcmp(insCode,residue[i]->insCode)))  {
1479             if (!strcmp(resName,residue[i]->name))
1480               return residue[i]; // it is there; just return the pointer
1481             else if (!Enforce)  {
1482 //            printf ( "1. sno=%i:%i, ic=[%s]:[%s] name=[%s]:[%s]\n",
1483 //                     seqNum,residue[i]->seqNum,
1484 //                     insCode,residue[i]->insCode,
1485 //                     resName,residue[i]->name );
1486               return NULL;       // duplicate seqNum and insCode!
1487             }
1488           }
1489         }
1490     } else  {
1491       for (i=0;i<nResidues;i++)
1492         if (residue[i])  {
1493           if ((seqNum==residue[i]->seqNum) &&
1494               (!residue[i]->insCode[0]))  {
1495             if (!strcmp(resName,residue[i]->name))
1496               return residue[i]; // it is there; just return the pointer
1497             else if (!Enforce)  {
1498 //            printf ( "2. sno=%i:%i, ic=[%s]:[%s] name=[%s]:[%s]\n",
1499 //                     seqNum,residue[i]->seqNum,
1500 //                     insCode,residue[i]->insCode,
1501 //                     resName,residue[i]->name );
1502               return NULL;       // duplicate seqNum and insCode!
1503             }
1504           }
1505         }
1506     }
1507 
1508     // expand the residue array, if necessary
1509     if (nResidues>=resLen)
1510       ExpandResidueArray ( 100 );
1511 
1512     // create new residue
1513     residue[nResidues] = newResidue();
1514     residue[nResidues]->SetChain ( this );
1515     residue[nResidues]->SetResID ( resName,seqNum,insCode );
1516     residue[nResidues]->index = nResidues;
1517     nResidues++;
1518 
1519     return residue[nResidues-1];
1520 
1521   }
1522 
ExpandResidueArray(int inc)1523   void  Chain::ExpandResidueArray ( int inc )  {
1524   PPResidue Residue1;
1525   int        i;
1526     resLen  += inc;
1527     Residue1 = new PResidue[resLen];
1528     for (i=0;i<nResidues;i++)
1529       Residue1[i] = residue[i];
1530     if (residue) delete[] residue;
1531     residue = Residue1;
1532     for (i=nResidues;i<resLen;i++)
1533       residue[i] = NULL;
1534   }
1535 
GetResidue(int seqNum,const InsCode insCode)1536   PResidue Chain::GetResidue ( int seqNum, const InsCode insCode )  {
1537   //   Returns pointer on residue, whose sequence number and
1538   // insert code are given in seqNum and insCode, respectively.
1539   // If such a residue is absent in the chain, returns NULL.
1540   int     i;
1541   bool isInsCode;
1542     if (insCode)  isInsCode = insCode[0]!=char(0);
1543             else  isInsCode = false;
1544     if (isInsCode)  {
1545       for (i=0;i<nResidues;i++)
1546         if (residue[i])  {
1547           if ((seqNum==residue[i]->seqNum) &&
1548               (!strcmp(insCode,residue[i]->insCode)))
1549             return residue[i];
1550         }
1551     } else  {
1552       for (i=0;i<nResidues;i++)
1553         if (residue[i])  {
1554           if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
1555             return residue[i];
1556         }
1557     }
1558     return NULL;
1559   }
1560 
GetResidueNo(int seqNum,const InsCode insCode)1561   int  Chain::GetResidueNo ( int seqNum, const InsCode insCode )  {
1562   //   GetResidueNo(..) returns the residue number in the chain's
1563   // residues table. Residues are numbered as 0..nres-1 as they appear
1564   // in the coordinate file.
1565   //   If residue is not found, the function returns -1.
1566   int      i;
1567   bool isInsCode;
1568     if (insCode)  isInsCode = insCode[0]!=char(0);
1569             else  isInsCode = false;
1570     if (isInsCode)  {
1571       for (i=0;i<nResidues;i++)
1572         if (residue[i])  {
1573           if ((seqNum==residue[i]->seqNum) &&
1574               (!strcmp(insCode,residue[i]->insCode)))
1575             return i;
1576         }
1577     } else  {
1578       for (i=0;i<nResidues;i++)
1579         if (residue[i])  {
1580           if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
1581             return i;
1582         }
1583     }
1584     return -1;
1585   }
1586 
GetResidueTable(PPResidue & resTable,int & NumberOfResidues)1587   void Chain::GetResidueTable ( PPResidue & resTable,
1588                                 int & NumberOfResidues )  {
1589     resTable         = residue;
1590     NumberOfResidues = nResidues;
1591   }
1592 
_ExcludeResidue(const ResName resName,int seqNum,const InsCode insCode)1593   int  Chain::_ExcludeResidue ( const ResName resName, int seqNum,
1594                                 const InsCode insCode )  {
1595   //   ExcludeResidue(..) excludes (but does not dispose!) a residue
1596   // from the chain. Returns 1 if the chain gets empty and 0 otherwise.
1597   int  i,k;
1598 
1599     if (!Exclude)  return 0;
1600 
1601     // find the residue
1602     k = -1;
1603     for (i=0;(i<nResidues) && (k<0);i++)
1604       if ((seqNum==residue[i]->seqNum)           &&
1605           (!strcmp(insCode,residue[i]->insCode)) &&
1606           (!strcmp(resName,residue[i]->name)))
1607         k = i;
1608 
1609     if (k>=0)  {
1610       for (i=k+1;i<nResidues;i++)  {
1611         residue[i-1] = residue[i];
1612         if (residue[i-1])
1613           residue[i-1]->index = i-1;
1614       }
1615       nResidues--;
1616       residue[nResidues] = NULL;
1617     }
1618 
1619     if (nResidues<=0)  return 1;
1620                  else  return 0;
1621 
1622   }
1623 
1624 
GetCoordSequence(pstr & seq)1625   void Chain::GetCoordSequence ( pstr & seq )  {
1626   //   GetCoorSequence(...) returns sequence inferred from list
1627   // of residues (which may differ from one in the file header).
1628   // The sequence is returned as a null-terminated string 'seq'.
1629   // On input, 'seq' should be either NULL or allocated (in which
1630   // case the original allocation will be released).
1631   int i,j;
1632 
1633     if (seq) delete[] seq;
1634     seq = new char[nResidues+1];
1635 
1636     j = 0;
1637     for (i=0;i<nResidues;i++)
1638       if (residue[i])
1639         Get1LetterCode ( residue[i]->GetResName(),seq[j++] );
1640     seq[j] = char(0);
1641 
1642   }
1643 
1644 
1645   //  ------------------  Deleting residues  --------------------------
1646 
DeleteResidue(int resNo)1647   int  Chain::DeleteResidue ( int resNo )  {
1648     if ((0<=resNo) && (resNo<nResidues))  {
1649       if (residue[resNo])  {
1650         Exclude = false;
1651         delete residue[resNo];
1652         residue[resNo] = NULL;
1653         Exclude = true;
1654         return 1;
1655       }
1656     }
1657     return 0;
1658   }
1659 
DeleteResidue(int seqNum,const InsCode insCode)1660   int  Chain::DeleteResidue ( int seqNum, const InsCode insCode )  {
1661   int i;
1662     if (insCode[0])  {
1663       for (i=0;i<nResidues;i++)
1664         if (residue[i])  {
1665           if ((seqNum==residue[i]->seqNum) &&
1666               (!strcmp(insCode,residue[i]->insCode)))  {
1667             Exclude = false;
1668             delete residue[i];
1669             residue[i] = NULL;
1670             Exclude = true;
1671             return 1;
1672           }
1673         }
1674     } else  {
1675       for (i=0;i<nResidues;i++)
1676         if (residue[i])  {
1677           if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))  {
1678             Exclude = false;
1679             delete residue[i];
1680             residue[i] = NULL;
1681             Exclude = true;
1682             return 1;
1683           }
1684         }
1685     }
1686     return 0;
1687   }
1688 
1689 
DeleteAllResidues()1690   int  Chain::DeleteAllResidues()  {
1691   int i,k;
1692     Exclude = false;
1693     k = 0;
1694     for (i=0;i<nResidues;i++)
1695       if (residue[i])  {
1696         delete residue[i];
1697         residue[i] = NULL;
1698         k++;
1699       }
1700     nResidues = 0;
1701     Exclude = true;
1702     return k;
1703   }
1704 
1705 
DeleteSolvent()1706   int  Chain::DeleteSolvent()  {
1707   int i,k;
1708     Exclude = false;
1709     k = 0;
1710     for (i=0;i<nResidues;i++)
1711       if (residue[i])  {
1712         if (residue[i]->isSolvent())  {
1713           delete residue[i];
1714           residue[i] = NULL;
1715           k++;
1716         }
1717       }
1718     Exclude = true;
1719     return k;
1720   }
1721 
1722 
TrimResidueTable()1723   void Chain::TrimResidueTable()  {
1724   int i,j;
1725     Exclude = false;
1726     j = 0;
1727     for (i=0;i<nResidues;i++)
1728       if (residue[i])  {
1729         if (residue[i]->nAtoms>0)  {
1730           if (j<i)  {
1731             residue[j] = residue[i];
1732             residue[j]->index = j;
1733             residue[i] = NULL;
1734           }
1735           j++;
1736         } else  {
1737           delete residue[i];
1738           residue[i] = NULL;
1739         }
1740       }
1741     nResidues = j;
1742     Exclude   = true;
1743   }
1744 
AddResidue(PResidue res)1745   int  Chain::AddResidue ( PResidue res )  {
1746   //  modify both CModel::Copy methods simultaneously!
1747   //
1748   //  Copy(PCModel,PPAtom,int&) copies atoms into array 'atom'
1749   // starting from position atom_index. 'atom' should be able to
1750   // accept all new atoms - no checks on the length of 'atom'
1751   // is being made. This function should not be used in applications.
1752     return InsResidue ( res,nResidues );
1753   }
1754 
1755   /*
1756   PCmmdbRoot mmdbRoot;
1757   PChain    chain1;
1758   int        i;
1759 
1760     for (i=0;i<nResidues;i++)
1761       if (residue[i]==res)  return -i;  // this residue is already there
1762 
1763     if (res)  {
1764 
1765       mmdbRoot = PCmmdbRoot(GetCoordHierarchy());
1766 
1767       // get space for new residue
1768       if (nResidues>=resLen)
1769         ExpandResidueArray ( 100 );
1770 
1771       if (res->GetCoordHierarchy())  {
1772         residue[nResidues] = newResidue();
1773         residue[nResidues]->SetChain ( this );
1774         residue[nResidues]->SetResID ( res->name,res->seqNum,res->insCode );
1775         if (mmdbRoot)  {
1776           // get space for new atoms
1777           mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
1778           residue[nResidues]->Copy ( res,mmdbRoot->Atom,mmdbRoot->nAtoms );
1779         } else  {
1780           for (i=0;i<res->nAtoms;i++)
1781             residue[nResidues]->AddAtom ( res->atom[i] );
1782         }
1783       } else  {
1784         residue[nResidues] = res;
1785         chain1 = res->GetChain();
1786         if (chain1)
1787           for (i=0;i<chain1->nResidues;i++)
1788             if (chain1->residue[i]==res)  {
1789               chain1->residue[i] = NULL;
1790               break;
1791             }
1792         residue[nResidues]->SetChain ( this );
1793         if (mmdbRoot)
1794           residue[nResidues]->CheckInAtoms();
1795       }
1796       nResidues++;
1797 
1798     }
1799 
1800     return nResidues;
1801 
1802   }
1803   */
1804 
InsResidue(PResidue res,int seqNum,const InsCode insCode)1805   int  Chain::InsResidue ( PResidue res, int seqNum,
1806                             const InsCode insCode )  {
1807     return InsResidue ( res,GetResidueNo(seqNum,insCode) );
1808   }
1809 
InsResidue(PResidue res,int pos)1810   int  Chain::InsResidue ( PResidue res, int pos )  {
1811   //   Inserts residue res onto position pos of the chain,
1812   // pos=0..nResidues-1 . Residues pos..nResidues-1 are
1813   // shifted up the chain.
1814   //   The function places new atoms on the top of atom
1815   // index. It is advisable to call
1816   // CmmdbRoot::PDBCleanup ( PDBCLEAN_INDEX ) after all
1817   // insertions are done.
1818   PRoot   mmdbRoot;
1819   PChain  chain1;
1820   int     i,pp;
1821 
1822     pp = IMax ( 0,IMin(nResidues,pos) );
1823 
1824     for (i=0;i<nResidues;i++)
1825       if (residue[i]==res)  return -i;  // this residue is already there
1826 
1827     if (res)  {
1828 
1829       mmdbRoot = PRoot(GetCoordHierarchy());
1830 
1831       // get space for new residue
1832       if (nResidues>=resLen)
1833         ExpandResidueArray ( 100 );
1834 
1835       // shift residues to the end of the chain as necessary
1836       for (i=nResidues;i>pp;i--)
1837         residue[i] = residue[i-1];
1838 
1839       // insert the new residue
1840       if (res->GetCoordHierarchy())  {
1841         residue[pp] = newResidue();
1842         residue[pp]->SetChain ( this );
1843         residue[pp]->SetResID ( res->name,res->seqNum,res->insCode );
1844         if (mmdbRoot)  {
1845           // get space for new atoms
1846           mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
1847           residue[pp]->_copy ( res,mmdbRoot->atom,mmdbRoot->nAtoms );
1848         } else  {
1849           for (i=0;i<res->nAtoms;i++)
1850             residue[pp]->AddAtom ( res->atom[i] );
1851         }
1852       } else  {
1853         residue[pp] = res;
1854         chain1 = res->GetChain();
1855         if (chain1)
1856           for (i=0;i<chain1->nResidues;i++)
1857             if (chain1->residue[i]==res)  {
1858               chain1->residue[i] = NULL;
1859               break;
1860             }
1861         residue[pp]->SetChain ( this );
1862         if (mmdbRoot)
1863           residue[pp]->CheckInAtoms();
1864       }
1865       nResidues++;
1866 
1867     }
1868 
1869     return nResidues;
1870 
1871   }
1872 
1873 
1874   // --------------------  Extracting atoms  -----------------------
1875 
GetNumberOfAtoms(bool countTers)1876   int Chain::GetNumberOfAtoms ( bool countTers )  {
1877   int i,na;
1878     na = 0;
1879     for (i=0;i<nResidues;i++)
1880       if (residue[i])  na += residue[i]->GetNumberOfAtoms ( countTers );
1881     return na;
1882   }
1883 
GetNumberOfAtoms(int seqNo,const InsCode insCode)1884   int Chain::GetNumberOfAtoms ( int seqNo, const InsCode insCode )  {
1885   PResidue res;
1886     res = GetResidue ( seqNo,insCode );
1887     if (res)  return res->nAtoms;
1888     return 0;
1889   }
1890 
GetNumberOfAtoms(int resNo)1891   int Chain::GetNumberOfAtoms ( int resNo )  {
1892     if ((0<=resNo) && (resNo<nResidues))  {
1893       if (residue[resNo])  return residue[resNo]->nAtoms;
1894     }
1895     return 0;
1896   }
1897 
GetAtom(int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)1898   PAtom Chain::GetAtom ( int            seqNo,
1899                          const InsCode  insCode,
1900                          const AtomName aname,
1901                          const Element  elmnt,
1902                          const AltLoc   aloc )  {
1903   PResidue res;
1904     res = GetResidue ( seqNo,insCode );
1905     if (res) return res->GetAtom ( aname,elmnt,aloc );
1906     return NULL;
1907   }
1908 
GetAtom(int seqNo,const InsCode insCode,int atomNo)1909   PAtom Chain::GetAtom ( int seqNo, const InsCode insCode,
1910                          int atomNo )  {
1911   PResidue res;
1912     res = GetResidue ( seqNo,insCode );
1913     if (res)  {
1914       if ((0<=atomNo) && (atomNo<res->nAtoms))
1915         return res->atom[atomNo];
1916     }
1917     return NULL;
1918   }
1919 
GetAtom(int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)1920   PAtom Chain::GetAtom ( int            resNo,
1921                          const AtomName aname,
1922                          const Element  elmnt,
1923                          const AltLoc   aloc )  {
1924     if ((0<=resNo) && (resNo<nResidues))  {
1925       if (residue[resNo])
1926         return residue[resNo]->GetAtom ( aname,elmnt,aloc );
1927     }
1928     return NULL;
1929   }
1930 
GetAtom(int resNo,int atomNo)1931   PAtom Chain::GetAtom ( int resNo, int atomNo )  {
1932   PResidue res;
1933     if ((0<=resNo) && (resNo<nResidues))  {
1934       res = residue[resNo];
1935       if (res)  {
1936         if ((0<=atomNo) && (atomNo<res->nAtoms))
1937           return res->atom[atomNo];
1938       }
1939     }
1940     return NULL;
1941   }
1942 
GetAtomTable(int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)1943   void Chain::GetAtomTable ( int seqNo, const InsCode insCode,
1944                            PPAtom & atomTable, int & NumberOfAtoms )  {
1945   PResidue res;
1946     atomTable     = NULL;
1947     NumberOfAtoms = 0;
1948     res = GetResidue ( seqNo,insCode );
1949     if (res)  {
1950       atomTable     = res->atom;
1951       NumberOfAtoms = res->nAtoms;
1952     }
1953   }
1954 
GetAtomTable(int resNo,PPAtom & atomTable,int & NumberOfAtoms)1955   void Chain::GetAtomTable ( int resNo, PPAtom & atomTable,
1956                               int & NumberOfAtoms )  {
1957   PResidue res;
1958     atomTable     = NULL;
1959     NumberOfAtoms = 0;
1960     if ((0<=resNo) && (resNo<nResidues))  {
1961       res = residue[resNo];
1962       if (res)  {
1963         atomTable     = res->atom;
1964         NumberOfAtoms = res->nAtoms;
1965       }
1966     }
1967   }
1968 
1969 
GetAtomTable1(int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)1970   void Chain::GetAtomTable1 ( int seqNo, const InsCode insCode,
1971                                PPAtom & atomTable, int & NumberOfAtoms )  {
1972   PResidue res;
1973     res = GetResidue ( seqNo,insCode );
1974     if (res)
1975       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
1976     else  {
1977       if (atomTable)  delete[] atomTable;
1978       atomTable     = NULL;
1979       NumberOfAtoms = 0;
1980     }
1981   }
1982 
GetAtomTable1(int resNo,PPAtom & atomTable,int & NumberOfAtoms)1983   void Chain::GetAtomTable1 ( int resNo, PPAtom & atomTable,
1984                                int & NumberOfAtoms )  {
1985   PResidue res;
1986     if ((0<=resNo) && (resNo<nResidues))
1987          res = residue[resNo];
1988     else res = NULL;
1989     if (res)
1990       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
1991     else  {
1992       if (atomTable)  delete[] atomTable;
1993       atomTable     = NULL;
1994       NumberOfAtoms = 0;
1995     }
1996   }
1997 
DeleteAtom(int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)1998   int Chain::DeleteAtom ( int            seqNo,
1999                            const InsCode  insCode,
2000                            const AtomName aname,
2001                            const Element  elmnt,
2002                            const AltLoc   aloc )  {
2003   PResidue res;
2004     res = GetResidue ( seqNo,insCode );
2005     if (res) return res->DeleteAtom ( aname,elmnt,aloc );
2006     return 0;
2007   }
2008 
DeleteAtom(int seqNo,const InsCode insCode,int atomNo)2009   int Chain::DeleteAtom ( int seqNo, const InsCode insCode,
2010                            int atomNo )  {
2011   PResidue res;
2012     res = GetResidue ( seqNo,insCode );
2013     if (res) return res->DeleteAtom ( atomNo );
2014     return 0;
2015   }
2016 
DeleteAtom(int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)2017   int Chain::DeleteAtom ( int            resNo,
2018                            const AtomName aname,
2019                            const Element  elmnt,
2020                            const AltLoc   aloc )  {
2021     if ((0<=resNo) && (resNo<nResidues))  {
2022       if (residue[resNo])
2023         return residue[resNo]->DeleteAtom ( aname,elmnt,aloc );
2024     }
2025     return 0;
2026   }
2027 
DeleteAtom(int resNo,int atomNo)2028   int Chain::DeleteAtom ( int resNo, int atomNo )  {
2029     if ((0<=resNo) && (resNo<nResidues))  {
2030       if (residue[resNo])
2031         return residue[resNo]->DeleteAtom ( atomNo );
2032     }
2033     return 0;
2034   }
2035 
2036 
DeleteAllAtoms(int seqNo,const InsCode insCode)2037   int Chain::DeleteAllAtoms ( int seqNo, const InsCode insCode )  {
2038   PResidue res;
2039     res = GetResidue ( seqNo,insCode );
2040     if (res) return res->DeleteAllAtoms();
2041     return 0;
2042   }
2043 
DeleteAllAtoms(int resNo)2044   int Chain::DeleteAllAtoms ( int resNo )  {
2045     if ((0<=resNo) && (resNo<nResidues))  {
2046       if (residue[resNo])
2047         return residue[resNo]->DeleteAllAtoms();
2048     }
2049     return 0;
2050   }
2051 
DeleteAllAtoms()2052   int Chain::DeleteAllAtoms()  {
2053   int i,k;
2054     k = 0;
2055     for (i=0;i<nResidues;i++)
2056       if (residue[i])
2057         k += residue[i]->DeleteAllAtoms();
2058     return k;
2059   }
2060 
DeleteAltLocs()2061   int Chain::DeleteAltLocs()  {
2062   //  This function leaves only alternative location with maximal
2063   // occupancy, if those are equal or unspecified, the one with
2064   // "least" alternative location indicator.
2065   //  The function returns the number of deleted. All tables remain
2066   // untrimmed, so that explicit trimming or calling FinishStructEdit()
2067   // is required.
2068   int i,n;
2069 
2070     n = 0;
2071     for (i=0;i<nResidues;i++)
2072       if (residue[i])  n += residue[i]->DeleteAltLocs();
2073 
2074     return n;
2075 
2076   }
2077 
2078 
AddAtom(int seqNo,const InsCode insCode,PAtom atom)2079   int Chain::AddAtom ( int seqNo, const InsCode insCode,
2080                         PAtom atom )  {
2081   PResidue res;
2082     res = GetResidue ( seqNo,insCode );
2083     if (res) return res->AddAtom ( atom );
2084     return 0;
2085   }
2086 
AddAtom(int resNo,PAtom atom)2087   int Chain::AddAtom ( int resNo, PAtom atom )  {
2088     if ((0<=resNo) && (resNo<nResidues))  {
2089       if (residue[resNo])
2090         return residue[resNo]->AddAtom ( atom );
2091     }
2092     return 0;
2093   }
2094 
2095 
Copy(PChain chain)2096   void  Chain::Copy ( PChain chain )  {
2097   // modify both Chain::_copy and Chain::Copy methods simultaneously!
2098   int i;
2099 
2100     FreeMemory();
2101 
2102     if (chain)  {
2103 
2104       CopyAnnotations ( chain );
2105 
2106       nResidues = chain->nResidues;
2107       resLen    = nResidues;
2108       if (nResidues>0)  {
2109         residue = new PResidue[nResidues];
2110         for (i=0;i<nResidues;i++)  {
2111           residue[i] = newResidue();
2112           residue[i]->SetChain ( this );
2113           residue[i]->Copy ( chain->residue[i] );
2114         }
2115       }
2116 
2117     }
2118 
2119   }
2120 
CopyAnnotations(PChain chain)2121   void  Chain::CopyAnnotations ( PChain chain )  {
2122     if (chain)  {
2123       strcpy ( chainID    ,chain->chainID     );
2124       strcpy ( prevChainID,chain->prevChainID );
2125       DBRef .Copy ( &(chain->DBRef)  );
2126       seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
2127       seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
2128       modRes.Copy ( &(chain->modRes) );  //  MODRES records
2129       Het   .Copy ( &(chain->Het)    );  //  HET    records
2130     }
2131   }
2132 
2133 
_copy(PChain chain)2134   void  Chain::_copy ( PChain chain )  {
2135   // modify both Chain::_copy and Chain::Copy methods simultaneously!
2136   int i;
2137 
2138     FreeMemory();
2139 
2140     strcpy ( chainID    ,chain->chainID     );
2141     strcpy ( prevChainID,chain->prevChainID );
2142 
2143     DBRef .Copy ( &(chain->DBRef)  );
2144     seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
2145     seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
2146     modRes.Copy ( &(chain->modRes) );  //  MODRES records
2147     Het   .Copy ( &(chain->Het)    );  //  HET    records
2148 
2149     nResidues = chain->nResidues;
2150     resLen    = nResidues;
2151     if (nResidues>0)  {
2152       residue = new PResidue[nResidues];
2153       for (i=0;i<nResidues;i++)  {
2154         residue[i] = newResidue();
2155         residue[i]->SetChain ( this );
2156         residue[i]->_copy ( chain->residue[i] );
2157       }
2158     }
2159 
2160   }
2161 
_copy(PChain chain,PPAtom atom,int & atom_index)2162   void  Chain::_copy ( PChain chain, PPAtom atom, int & atom_index )  {
2163   // modify both Chain::_copy and Chain::Copy methods simultaneously!
2164   int i;
2165 
2166     FreeMemory();
2167 
2168     strcpy ( chainID    ,chain->chainID     );
2169     strcpy ( prevChainID,chain->prevChainID );
2170 
2171     DBRef .Copy ( &(chain->DBRef)  );
2172     seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
2173     seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
2174     modRes.Copy ( &(chain->modRes) );  //  MODRES records
2175     Het   .Copy ( &(chain->Het)    );  //  HET    records
2176 
2177     nResidues = chain->nResidues;
2178     resLen    = nResidues;
2179     if (nResidues>0)  {
2180       residue = new PResidue[nResidues];
2181       for (i=0;i<nResidues;i++)
2182         if (chain->residue[i])  {
2183           residue[i] = newResidue();
2184           residue[i]->SetChain ( this );
2185           residue[i]->_copy ( chain->residue[i],atom,atom_index );
2186         } else
2187           residue[i] = NULL;
2188     }
2189 
2190   }
2191 
2192   /*
2193   void  Chain::Duplicate ( PChain Chain )  {
2194   int i;
2195 
2196     FreeMemory();
2197 
2198     strcpy ( chainID    ,chain->chainID     );
2199     strcpy ( prevChainID,chain->prevChainID );
2200 
2201     DBReference.Copy ( &(chain->DBReference) );
2202     SeqAdv     .Copy ( &(chain->SeqAdv)      );  //  SEQADV records
2203     SeqRes     .Copy ( &(chain->SeqRes)      );  //  SEQRES data
2204     ModRes     .Copy ( &(chain->ModRes)      );  //  MODRES records
2205     Het        .Copy ( &(chain->Het)         );  //  HET    records
2206 
2207     nResidues = chain->nResidues;
2208     resLen    = nResidues;
2209     if (nResidues>0)  {
2210       Residue = new PResidue[nResidues];
2211       for (i=0;i<nResidues;i++)  {
2212         residue[i] = newResidue();
2213         residue[i]->SetChain ( this );
2214         residue[i]->Duplicate ( chain->residue[i] );
2215       }
2216     }
2217 
2218   }
2219   */
2220 
GetEntryID()2221   cpstr  Chain::GetEntryID()  {
2222     if (model)  return model->GetEntryID();
2223           else  return pstr("");
2224   }
2225 
SetEntryID(const IDCode idCode)2226   void  Chain::SetEntryID ( const IDCode idCode )  {
2227     if (model) model->SetEntryID ( idCode );
2228   }
2229 
GetModelNum()2230   int   Chain::GetModelNum()  {
2231     if (model)  return model->GetSerNum();
2232     return 0;
2233   }
2234 
GetChainID(pstr ChID)2235   cpstr  Chain::GetChainID ( pstr ChID )  {
2236     ChID[0] = char(0);
2237     if (model)
2238          sprintf ( ChID,"/%i/",model->GetSerNum() );
2239     else strcpy  ( ChID,"/-/" );
2240     strcat ( ChID,chainID );
2241     return ChID;
2242   }
2243 
2244 
GetAtomStatistics(RAtomStat AS)2245   void  Chain::GetAtomStatistics  ( RAtomStat AS )  {
2246     AS.Init();
2247     CalAtomStatistics ( AS );
2248     AS.Finish();
2249   }
2250 
CalAtomStatistics(RAtomStat AS)2251   void  Chain::CalAtomStatistics ( RAtomStat AS )  {
2252   int i;
2253     for (i=0;i<nResidues;i++)
2254       if (residue[i])
2255         residue[i]->CalAtomStatistics ( AS );
2256   }
2257 
ApplyTransform(mat44 & TMatrix)2258   void  Chain::ApplyTransform ( mat44 & TMatrix )  {
2259   // transforms all coordinates by multiplying with matrix TMatrix
2260   int i;
2261     for (i=0;i<nResidues;i++)
2262       if (residue[i])  residue[i]->ApplyTransform ( TMatrix );
2263   }
2264 
isSolventChain()2265   bool Chain::isSolventChain()  {
2266   // returns true if chain contains only solvent molecules
2267   bool B,P;
2268   int     i;
2269     B = true;
2270     P = false;
2271     for (i=0;(i<nResidues) && B;i++)
2272       if (residue[i])  {
2273         P = true;
2274         B = residue[i]->isSolvent();
2275       }
2276     return (B && P);
2277   }
2278 
isInSelection(int selHnd)2279   bool Chain::isInSelection ( int selHnd )  {
2280   PRoot mmdbRoot = (PRoot)GetCoordHierarchy();
2281   PMask mask;
2282     if (mmdbRoot)  {
2283       mask = mmdbRoot->GetSelMask ( selHnd );
2284       if (mask)  return CheckMask ( mask );
2285     }
2286     return false;
2287   }
2288 
isAminoacidChain()2289   bool Chain::isAminoacidChain()  {
2290   // returns true if chain contains at least one aminoacid residue
2291   bool B,P;
2292   int     i;
2293     B = false;
2294     P = false;
2295     for (i=0;(i<nResidues) && (!B);i++)
2296       if (residue[i])  {
2297         P = true;
2298         B = residue[i]->isAminoacid();
2299       }
2300     return (B && P);
2301   }
2302 
isNucleotideChain()2303   bool Chain::isNucleotideChain()  {
2304   // returns true if chain contains at least one nucleotide residue
2305   bool B,P;
2306   int     i;
2307     B = false;
2308     P = false;
2309     for (i=0;(i<nResidues) && (!B);i++)
2310       if (residue[i])  {
2311         P = true;
2312         B = residue[i]->isNucleotide();
2313       }
2314     return (B && P);
2315   }
2316 
CheckID(const ChainID chID)2317   int  Chain::CheckID ( const ChainID chID )  {
2318     if (chID)  {
2319       if (!strcmp(chID,chainID))  return 1;
2320     }
2321     return 0;
2322   }
2323 
CheckIDS(cpstr CID)2324   int  Chain::CheckIDS ( cpstr CID )  {
2325   ChainID  chn;
2326   InsCode  inscode;
2327   ResName  resname;
2328   AtomName atm;
2329   Element  elm;
2330   AltLoc   aloc;
2331   int      mdl,sn,rc;
2332 
2333     rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
2334                          atm,elm,aloc,NULL );
2335     if (rc>=0)  {
2336       if (!strcmp(chn,chainID))  return 1;
2337     }
2338     return 0;
2339 
2340   }
2341 
GetNumberOfDBRefs()2342   int  Chain::GetNumberOfDBRefs()  {
2343     return  DBRef.Length();
2344   }
2345 
GetDBRef(int dbRefNo)2346   PDBReference  Chain::GetDBRef ( int dbRefNo )  {
2347     return  (PDBReference)DBRef.GetContainerClass ( dbRefNo );
2348   }
2349 
2350 
MaskAtoms(PMask mask)2351   void  Chain::MaskAtoms ( PMask mask )  {
2352   int i;
2353     for (i=0;i<nResidues;i++)
2354       if (residue[i])  residue[i]->MaskAtoms ( mask );
2355   }
2356 
MaskResidues(PMask mask)2357   void  Chain::MaskResidues ( PMask mask )  {
2358   int i;
2359     for (i=0;i<nResidues;i++)
2360       if (residue[i])  residue[i]->SetMask ( mask );
2361   }
2362 
UnmaskAtoms(PMask mask)2363   void  Chain::UnmaskAtoms ( PMask mask )  {
2364   int i;
2365     for (i=0;i<nResidues;i++)
2366       if (residue[i])  residue[i]->UnmaskAtoms ( mask );
2367   }
2368 
UnmaskResidues(PMask mask)2369   void  Chain::UnmaskResidues ( PMask mask )  {
2370   int i;
2371     for (i=0;i<nResidues;i++)
2372       if (residue[i])  residue[i]->RemoveMask ( mask );
2373   }
2374 
2375 
2376 
2377 
2378   // -------  user-defined data handlers
2379 
PutUDData(int UDDhandle,int iudd)2380   int  Chain::PutUDData ( int UDDhandle, int iudd )  {
2381     if (UDDhandle & UDRF_CHAIN)
2382           return  UDData::putUDData ( UDDhandle,iudd );
2383     else  return  UDDATA_WrongUDRType;
2384   }
2385 
PutUDData(int UDDhandle,realtype rudd)2386   int  Chain::PutUDData ( int UDDhandle, realtype rudd )  {
2387     if (UDDhandle & UDRF_CHAIN)
2388           return  UDData::putUDData ( UDDhandle,rudd );
2389     else  return  UDDATA_WrongUDRType;
2390   }
2391 
PutUDData(int UDDhandle,cpstr sudd)2392   int  Chain::PutUDData ( int UDDhandle, cpstr sudd )  {
2393     if (UDDhandle & UDRF_CHAIN)
2394           return  UDData::putUDData ( UDDhandle,sudd );
2395     else  return  UDDATA_WrongUDRType;
2396   }
2397 
GetUDData(int UDDhandle,int & iudd)2398   int  Chain::GetUDData ( int UDDhandle, int & iudd )  {
2399     if (UDDhandle & UDRF_CHAIN)
2400           return  UDData::getUDData ( UDDhandle,iudd );
2401     else  return  UDDATA_WrongUDRType;
2402   }
2403 
GetUDData(int UDDhandle,realtype & rudd)2404   int  Chain::GetUDData ( int UDDhandle, realtype & rudd )  {
2405     if (UDDhandle & UDRF_CHAIN)
2406           return  UDData::getUDData ( UDDhandle,rudd );
2407     else  return  UDDATA_WrongUDRType;
2408   }
2409 
GetUDData(int UDDhandle,pstr sudd,int maxLen)2410   int  Chain::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
2411     if (UDDhandle & UDRF_CHAIN)
2412           return  UDData::getUDData ( UDDhandle,sudd,maxLen );
2413     else  return  UDDATA_WrongUDRType;
2414   }
2415 
GetUDData(int UDDhandle,pstr & sudd)2416   int  Chain::GetUDData ( int UDDhandle, pstr & sudd )  {
2417     if (UDDhandle & UDRF_CHAIN)
2418           return  UDData::getUDData ( UDDhandle,sudd );
2419     else  return  UDDATA_WrongUDRType;
2420   }
2421 
2422 
2423   //  -------------------------------------------------------------------
2424 
2425   DefineClass(SortResidues)
2426 
2427   class QSortResidues : public QuickSort  {
2428     public :
QSortResidues()2429       QSortResidues() : QuickSort() {}
2430       int  Compare ( int i, int j );
2431       void Swap    ( int i, int j );
2432       void Sort    ( PPResidue res, int nresidues );
2433   };
2434 
Compare(int i,int j)2435   int QSortResidues::Compare ( int i, int j )  {
2436   int diff;
2437     diff = ((PPResidue)data)[i]->seqNum - ((PPResidue)data)[j]->seqNum;
2438     if (diff==0)
2439       diff = strcmp( (PPResidue(data))[i]->insCode,
2440                      (PPResidue(data))[j]->insCode );
2441     if (diff>0)  return  1;
2442     if (diff<0)  return -1;
2443     return 0;
2444   }
2445 
Swap(int i,int j)2446   void QSortResidues::Swap ( int i, int j )  {
2447   PResidue res;
2448     res = ((PPResidue)data)[i];
2449     ((PPResidue)data)[i] = ((PPResidue)data)[j];
2450     ((PPResidue)data)[j] = res;
2451   }
2452 
Sort(PPResidue res,int nresidues)2453   void QSortResidues::Sort ( PPResidue res, int nresidues )  {
2454     QuickSort::Sort ( &(res[0]),nresidues );
2455   }
2456 
SortResidues()2457   void  Chain::SortResidues()  {
2458   QSortResidues SR;
2459     TrimResidueTable();
2460     SR.Sort ( residue,nResidues );
2461   }
2462 
GetNofModResidues()2463   int  Chain::GetNofModResidues()  {
2464     return modRes.Length();
2465   }
2466 
GetModResidue(int modResNo)2467   PModRes  Chain::GetModResidue ( int modResNo )  {
2468     return  PModRes(modRes.GetContainerClass(modResNo));
2469   }
2470 
write(io::RFile f)2471   void  Chain::write ( io::RFile f )  {
2472   int  i;
2473   byte Version=2;
2474   bool compactBinary = false;
2475 
2476     PManager M = GetCoordHierarchy();
2477     if (M)
2478       compactBinary = M->isCompactBinary();
2479 
2480     f.WriteByte ( &Version       );
2481     f.WriteBool ( &compactBinary );
2482     f.WriteTerLine ( chainID,false );
2483 
2484     f.WriteInt ( &nResidues );
2485     for (i=0;i<nResidues;i++)
2486       residue[i]->write ( f );
2487 
2488     if (!compactBinary)  {
2489 
2490       UDData::write ( f );
2491 
2492       f.WriteTerLine ( prevChainID,false );
2493 
2494       DBRef .write ( f );  //  Database reference
2495       seqAdv.write ( f );  //  SEQADV records
2496       seqRes.write ( f );  //  SEQRES data
2497       modRes.write ( f );  //  MODRES records
2498       Het   .write ( f );  //  HET    records
2499 
2500     }
2501 
2502   }
2503 
read(io::RFile f)2504   void  Chain::read ( io::RFile f )  {
2505   //   The Atom array in CmmdbRoot must be already read
2506   // prior to calling this function!
2507   int  i;
2508   byte Version;
2509   bool compactBinary;
2510 
2511     FreeMemory();
2512 
2513     f.ReadByte ( &Version       );
2514     f.ReadBool ( &compactBinary );
2515     f.ReadTerLine ( chainID,false );
2516 
2517     SetChain ( chainID );
2518 
2519     f.ReadInt ( &nResidues );
2520     resLen = nResidues;
2521     if (nResidues>0)  {
2522       residue = new PResidue[nResidues];
2523       for (i=0;i<nResidues;i++)  {
2524         residue[i] = newResidue();
2525         residue[i]->SetChain ( this );
2526         residue[i]->read ( f );
2527       }
2528     }
2529 
2530     if (!compactBinary)  {
2531 
2532       UDData::read ( f );
2533 
2534       f.ReadTerLine ( prevChainID,false );
2535 
2536       DBRef .read ( f );   //  Database reference
2537       seqAdv.read ( f );   //  SEQADV records
2538       seqRes.read ( f );   //  SEQRES data
2539       modRes.read ( f );   //  MODRES records
2540       Het   .read ( f );   //  HET    records
2541 
2542     }
2543 
2544   }
2545 
2546 
2547   MakeFactoryFunctions(Chain)
2548 
2549 }  // namespace mmdb
2550 
2551 
2552 // ===================================================================
2553 
2554   /*
2555 void  TestChain() {
2556 //  reads from 'in.chain', writes into
2557 //  'out.chain' and 'abin.chain'
2558 CFile    f;
2559 char     S[81];
2560 PChain  Chain;
2561 
2562   Chain = newChain();
2563 
2564   f.assign ( "in.chain",true );
2565   if (f.reset()) {
2566     while (!f.FileEnd()) {
2567       f.ReadLine ( S,sizeof(S) );
2568       chain->ConvertPDBString ( S );
2569     }
2570     f.shut();
2571   } else {
2572     printf ( " Can't open input file 'in.chain' \n" );
2573     delete Chain;
2574     return;
2575   }
2576 
2577   f.assign ( "out.chain",true );
2578   if (f.rewrite()) {
2579     chain->PDBASCIIDump ( f );
2580     f.shut();
2581   } else {
2582     printf ( " Can't open output file 'out.chain' \n" );
2583     delete Chain;
2584     return;
2585   }
2586 
2587 
2588   f.assign ( "mmdb.chain.bin",false );
2589   if (f.rewrite()) {
2590     chain->write ( f );
2591     f.shut();
2592   } else {
2593     printf ( "  Can't open binary chain file for writing.\n" );
2594     delete Chain;
2595     return;
2596   }
2597 
2598   delete Chain;
2599   printf ( "   Chain deleted.\n" );
2600 
2601   Chain = newChain();
2602   if (f.reset()) {
2603     chain->read ( f );
2604     f.shut();
2605   } else {
2606     printf ( "  Can't open binary chain file for reading.\n" );
2607     delete Chain;
2608     return;
2609   }
2610 
2611   f.assign ( "abin.chain",true );
2612   if (f.rewrite()) {
2613     chain->PDBASCIIDump ( f );
2614     f.shut();
2615   } else
2616     printf ( " Can't open output file 'abin.chain' \n" );
2617 
2618   delete Chain;
2619 
2620 }
2621   */
2622