1 /*  $Id: data_manager.cpp 123357 2008-04-01 19:42:38Z thiessen $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors:  Paul Thiessen
27 *
28 * File Description:
29 *      class to manage different root ASN data types
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbistd.hpp>
36 #include <serial/iterator.hpp>
37 
38 #include <objects/ncbimime/Entrez_general.hpp>
39 #include <objects/ncbimime/Biostruc_align.hpp>
40 #include <objects/ncbimime/Biostruc_align_seq.hpp>
41 #include <objects/ncbimime/Biostruc_seq.hpp>
42 #include <objects/ncbimime/Biostruc_seqs.hpp>
43 #include <objects/ncbimime/Biostruc_seqs_aligns_cdd.hpp>
44 #include <objects/ncbimime/Bundle_seqs_aligns.hpp>
45 #include <objects/seqset/Bioseq_set.hpp>
46 #include <objects/mmdb3/Biostruc_feature_set.hpp>
47 #include <objects/cdd/Cdd_descr_set.hpp>
48 #include <objects/cdd/Cdd_descr.hpp>
49 #include <objects/cdd/Cdd_id.hpp>
50 #include <objects/cdd/Global_id.hpp>
51 #include <objects/cdd/Cdd_id_set.hpp>
52 #include <objects/seqalign/seqalign__.hpp>
53 #include <objects/general/Object_id.hpp>
54 
55 #include "remove_header_conflicts.hpp"
56 
57 #include "asn_reader.hpp"
58 #include "data_manager.hpp"
59 #include "structure_set.hpp"
60 #include "sequence_set.hpp"
61 #include "alignment_set.hpp"
62 #include "cn3d_tools.hpp"
63 
64 #include <algo/structure/cd_utils/cuCD.hpp>
65 
66 USING_NCBI_SCOPE;
67 USING_SCOPE(objects);
68 
69 
BEGIN_SCOPE(Cn3D)70 BEGIN_SCOPE(Cn3D)
71 
72 ASNDataManager::ASNDataManager(ncbi::objects::CNcbi_mime_asn1 *mime)
73 {
74     mimeData.Reset(mime);
75     Load();
76 }
77 
ASNDataManager(ncbi::objects::CCdd * cdd)78 ASNDataManager::ASNDataManager(ncbi::objects::CCdd *cdd)
79 {
80     cddData.Reset(cdd);
81     Load();
82 }
83 
~ASNDataManager(void)84 ASNDataManager::~ASNDataManager(void)
85 {
86 }
87 
Load(void)88 void ASNDataManager::Load(void)
89 {
90     // initialization
91     seqEntryList = NULL;
92     masterBiostruc = NULL;
93     biostrucList = NULL;
94     biostrucModelType = eModel_type_ncbi_all_atom;  // default, for CDD's
95     sequenceAlignments = NULL;
96     structureAlignments = NULL;
97     bundleImports = NULL;
98     cddUpdates = NULL;
99     dataChanged = 0;
100 
101     // remove consensus sequence, then do a check over the whole tree to make sure any reference to it is gone
102     if (GetInternalCDDData()) {
103         RemoveConsensusFromCDD();
104         for (CTypeConstIterator < CSeq_id > i(ConstBegin(*(GetInternalCDDData()))); i; ++i) {
105             if (i->IsLocal() && i->GetLocal().IsStr() && i->GetLocal().GetStr() == "consensus") {
106                 WARNINGMSG("ASNDataManager::Load() - consensus still referenced in the data: " << i.GetContext());
107                 break;
108             }
109         }
110     } else if (mimeData.NotEmpty()) {
111         for (CTypeConstIterator < CSeq_id > i(ConstBegin(mimeData.GetObject())); i; ++i) {
112             if (i->IsLocal() && i->GetLocal().IsStr() && i->GetLocal().GetStr() == "consensus") {
113                 WARNINGMSG("ASNDataManager::Load() - a consensus is present in the data: " << i.GetContext());
114                 break;
115             }
116         }
117     }
118 
119     // mime
120     if (mimeData.NotEmpty()) {
121         if (mimeData->IsEntrez()) {
122             if (mimeData->GetEntrez().GetData().IsStructure())
123                 masterBiostruc = &(mimeData->SetEntrez().SetData().SetStructure());
124         }
125 
126         else if (mimeData->IsAlignstruc()) {
127             seqEntryList = &(mimeData->SetAlignstruc().SetSequences());
128             masterBiostruc = &(mimeData->SetAlignstruc().SetMaster());
129             biostrucList = &(mimeData->SetAlignstruc().SetSlaves());
130             structureAlignments = &(mimeData->SetAlignstruc().SetAlignments());
131             sequenceAlignments = &(mimeData->SetAlignstruc().SetSeqalign());
132         }
133 
134         else if (mimeData->IsAlignseq()) {
135             seqEntryList = &(mimeData->SetAlignseq().SetSequences());
136             sequenceAlignments = &(mimeData->SetAlignseq().SetSeqalign());
137         }
138 
139         else if (mimeData->IsStrucseq()) {
140             seqEntryList = &(mimeData->SetStrucseq().SetSequences());
141             masterBiostruc = &(mimeData->SetStrucseq().SetStructure());
142         }
143 
144         else if (mimeData->IsStrucseqs()) {
145             seqEntryList = &(mimeData->SetStrucseqs().SetSequences());
146             masterBiostruc = &(mimeData->SetStrucseqs().SetStructure());
147             sequenceAlignments = &(mimeData->SetStrucseqs().SetSeqalign());
148         }
149 
150         else if (mimeData->IsGeneral()) {
151             if (mimeData->GetGeneral().IsSetStructures())
152                 biostrucList = &(mimeData->SetGeneral().SetStructures());
153 
154             if (mimeData->GetGeneral().IsSetStructure_type())
155                 // assume structure-type values match MMDB's Model-type
156                 biostrucModelType = (EModel_type) mimeData->GetGeneral().GetStructure_type();
157 
158             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle()) {
159                 if (mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetSequences())
160                     seqEntryList = &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetSequences());
161                 if (mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetStrucaligns())
162                     structureAlignments =
163                         &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetStrucaligns());
164                 if (mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetSeqaligns())
165                     sequenceAlignments =
166                         &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetSeqaligns());
167                 if (mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetImports()) {
168                     bundleImports = &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetImports());
169                     // make "fake" Update-aligns from imports (to pass to alignment manager)
170                     SeqAnnotList::iterator i,
171                         ie = mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetImports().end();
172                     for (i=mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetImports().begin();
173                          i!= ie; ++i) {
174                         CRef < CUpdate_align > update(new CUpdate_align());
175                         update->SetSeqannot(**i);
176                         update->SetType(CUpdate_align::eType_other);
177                         bundleImportsFaked.push_back(update);
178                     }
179                 }
180             }
181 
182             else {  // cdd
183                 if (mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetSequences()) {
184                     if (mimeData->GetGeneral().GetSeq_align_data().GetCdd().GetSequences().IsSeq()) {
185                         // convert Seq-entry type from seq to set
186                         CRef < CSeq_entry > seqEntry(
187                             &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetSequences()));
188                         mimeData->SetGeneral().SetSeq_align_data().SetCdd().ResetSequences();
189                         mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetSequences().
190                             SetSet().SetSeq_set().push_back(seqEntry);
191                     }
192                     seqEntryList =
193                         &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetSequences().SetSet().SetSeq_set());
194                 }
195                 if (mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetFeatures())
196                     structureAlignments = &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetFeatures());
197                 if (mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetSeqannot())
198                     sequenceAlignments = &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetSeqannot());
199                 if (mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetPending())
200                     cddUpdates = &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetPending());
201             }
202         }
203 
204         else
205             ERRORMSG("Unrecognized mime type!");
206     }
207 
208     // CDD
209     else {
210         if (cddData->IsSetSequences()) {
211             if (cddData->GetSequences().IsSeq()) {
212                 // convert Seq-entry type from seq to set
213                 CRef < CSeq_entry > seqEntry(&(cddData->SetSequences()));
214                 cddData->ResetSequences();
215                 cddData->SetSequences().SetSet().SetSeq_set().push_back(seqEntry);
216             }
217             seqEntryList = &(cddData->SetSequences().SetSet().SetSeq_set());
218         }
219         if (cddData->IsSetFeatures())
220             structureAlignments = &(cddData->SetFeatures());
221         if (cddData->IsSetSeqannot())
222             sequenceAlignments = &(cddData->SetSeqannot());
223         if (cddData->IsSetPending())
224             cddUpdates = &(cddData->SetPending());
225     }
226 
227     // sequence list is interpreted differently for single structure
228     isSingleStructure = (mimeData.NotEmpty() &&
229         (mimeData->IsStrucseq() ||
230             (mimeData->IsGeneral() &&
231                 !sequenceAlignments && !structureAlignments &&
232                 biostrucList && biostrucList->size() == 1)));
233     TRACEMSG("is single structure: " << (isSingleStructure ? "yes" : "no"));
234 
235     // pre-screen sequence alignments to make sure they're all a type we can deal with
236     if (sequenceAlignments) {
237         list < CRef < CSeq_align > > validAlignments;
238         SeqAnnotList::const_iterator n, ne = sequenceAlignments->end();
239         for (n=sequenceAlignments->begin(); n!=ne; ++n) {
240 
241             if (!n->GetObject().GetData().IsAlign()) {
242                 ERRORMSG("Warning - confused by seqannot data format");
243                 continue;
244             }
245             if (n != sequenceAlignments->begin()) TRACEMSG("multiple Seq-annots");
246 
247             CSeq_annot::C_Data::TAlign::const_iterator
248                 a, ae = n->GetObject().GetData().GetAlign().end();
249             for (a=n->GetObject().GetData().GetAlign().begin(); a!=ae; ++a) {
250 
251                 // verify this is a type of alignment we can deal with
252                 if (!(a->GetObject().GetType() != CSeq_align::eType_partial ||
253                     a->GetObject().GetType() != CSeq_align::eType_diags) ||
254                     !a->GetObject().IsSetDim() || a->GetObject().GetDim() != 2 ||
255                     (!a->GetObject().GetSegs().IsDendiag() && !a->GetObject().GetSegs().IsDenseg())) {
256                     ERRORMSG("Warning - confused by alignment type");
257                     continue;
258                 }
259                 validAlignments.push_back(*a);
260             }
261         }
262 
263         sequenceAlignments->clear();
264         if (validAlignments.size() == 0) {
265             ERRORMSG("Warning - no valid Seq-aligns present");
266             sequenceAlignments = NULL;
267         } else {
268             sequenceAlignments->push_back(CRef < CSeq_annot > (new CSeq_annot()));
269             // copy list of valid alignments only
270             sequenceAlignments->front()->SetData().SetAlign() = validAlignments;
271         }
272     }
273 }
274 
RemoveConsensusFromCDD(void)275 void ASNDataManager::RemoveConsensusFromCDD(void)
276 {
277     CCdd *cdd = GetInternalCDDData();
278     if (!cdd)
279         return;
280 
281     int result = cd_utils::PurgeConsensusSequences((cd_utils::CCdCore *) cdd, true);
282     TRACEMSG("PurgeConsensusSequences() removed " << result << " sequence(s)");
283 //    string err;
284 //    WriteASNToFile("Cdd.txt", *cdd, false, &err);
285 }
286 
ConvertMimeDataToCDD(const std::string & cddName)287 bool ASNDataManager::ConvertMimeDataToCDD(const std::string& cddName)
288 {
289     // if we have CDD data already, this is really easy
290     if (IsCDDInMime()) {
291         cddData.Reset(GetInternalCDDData());
292     }
293     else if (IsCDD()){
294         return true;    // nothing to do
295     }
296 
297     // otherwise, splice together from mime data
298     else {
299         CRef < CCdd > cdd(new CCdd());
300         cdd->SetName(cddName);
301 
302         // make up a local id
303         static int localID = 1;
304         CRef < CCdd_id > id(new CCdd_id());
305         cdd->SetId().Set().push_back(id);
306         CNcbiOstrstream oss;
307         oss << "loc_" << localID++;
308         id->SetGid().SetAccession((string) CNcbiOstrstreamToString(oss));
309 
310         // fill in data
311         if (!seqEntryList) {
312             ERRORMSG("can't find sequences to put into new Cdd");
313             return false;
314         }
315         cdd->SetSequences().SetSet().SetSeq_set() = *seqEntryList;
316         if (!sequenceAlignments) {
317             ERRORMSG("can't find sequence alignments to put into new Cdd");
318             return false;
319         }
320         cdd->SetSeqannot() = *sequenceAlignments;
321         if (structureAlignments)
322             cdd->SetFeatures(*structureAlignments);
323         if (cddUpdates)
324             cdd->SetPending() = *cddUpdates;
325         if (bundleImportsFaked.size() > 0)
326             cdd->SetPending().splice(cdd->SetPending().end(), bundleImportsFaked);
327 
328         cddData.Reset(cdd.GetPointer());
329     }
330 
331     mimeData.Reset();
332     Load();
333     return true;
334 }
335 
GetOrCreateSequenceAlignments(void)336 ASNDataManager::SeqAnnotList * ASNDataManager::GetOrCreateSequenceAlignments(void)
337 {
338     // if necessary, convert mime data into general type that has a place for alignments
339     if (!sequenceAlignments && mimeData.NotEmpty() && !mimeData->IsGeneral())
340         ConvertMimeToGeneral();
341 
342     if (!sequenceAlignments && mimeData.NotEmpty() && mimeData->IsGeneral() &&
343             mimeData->GetGeneral().GetSeq_align_data().IsBundle())
344         sequenceAlignments =
345             &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetSeqaligns());
346     return sequenceAlignments;
347 }
348 
GetStyleDictionary(void) const349 const CCn3d_style_dictionary * ASNDataManager::GetStyleDictionary(void) const
350 {
351     if (mimeData.NotEmpty()) {
352         if (mimeData->IsAlignstruc() && mimeData->GetAlignstruc().IsSetStyle_dictionary())
353             return &(mimeData->GetAlignstruc().GetStyle_dictionary());
354         else if (mimeData->IsAlignseq() && mimeData->GetAlignseq().IsSetStyle_dictionary())
355             return &(mimeData->GetAlignseq().GetStyle_dictionary());
356         else if (mimeData->IsStrucseq() && mimeData->GetStrucseq().IsSetStyle_dictionary())
357             return &(mimeData->GetStrucseq().GetStyle_dictionary());
358         else if (mimeData->IsStrucseqs() && mimeData->GetStrucseqs().IsSetStyle_dictionary())
359             return &(mimeData->GetStrucseqs().GetStyle_dictionary());
360         else if (mimeData->IsGeneral()) {
361             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle() &&
362                 mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetStyle_dictionary())
363                 return &(mimeData->GetGeneral().GetSeq_align_data().GetBundle().GetStyle_dictionary());
364             else if (mimeData->GetGeneral().GetSeq_align_data().IsCdd() &&
365                      mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetStyle_dictionary())
366                 return &(mimeData->GetGeneral().GetSeq_align_data().GetCdd().GetStyle_dictionary());
367         }
368     } else if (cddData->IsSetStyle_dictionary())
369         return &(cddData->GetStyle_dictionary());
370 
371     return NULL;
372 }
373 
SetStyleDictionary(ncbi::objects::CCn3d_style_dictionary & styles)374 void ASNDataManager::SetStyleDictionary(ncbi::objects::CCn3d_style_dictionary& styles)
375 {
376     if (mimeData.NotEmpty()) {
377         if (mimeData->IsAlignstruc()) mimeData->SetAlignstruc().SetStyle_dictionary(styles);
378         else if (mimeData->IsAlignseq()) mimeData->SetAlignseq().SetStyle_dictionary(styles);
379         else if (mimeData->IsStrucseq()) mimeData->SetStrucseq().SetStyle_dictionary(styles);
380         else if (mimeData->IsStrucseqs()) mimeData->SetStrucseqs().SetStyle_dictionary(styles);
381         else if (mimeData->IsGeneral()) {
382             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle())
383                 mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetStyle_dictionary(styles);
384             else
385                 mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetStyle_dictionary(styles);
386         }
387     } else
388         cddData->SetStyle_dictionary(styles);
389 }
390 
RemoveStyleDictionary(void)391 void ASNDataManager::RemoveStyleDictionary(void)
392 {
393     if (mimeData.NotEmpty()) {
394         if (mimeData->IsAlignstruc()) mimeData->SetAlignstruc().ResetStyle_dictionary();
395         else if (mimeData->IsAlignseq()) mimeData->SetAlignseq().ResetStyle_dictionary();
396         else if (mimeData->IsStrucseq()) mimeData->SetStrucseq().ResetStyle_dictionary();
397         else if (mimeData->IsStrucseqs()) mimeData->SetStrucseqs().ResetStyle_dictionary();
398         else if (mimeData->IsGeneral()) {
399             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle())
400                 mimeData->SetGeneral().SetSeq_align_data().SetBundle().ResetStyle_dictionary();
401             else
402                 mimeData->SetGeneral().SetSeq_align_data().SetCdd().ResetStyle_dictionary();
403         }
404     } else
405         cddData->ResetStyle_dictionary();
406 }
407 
GetUserAnnotations(void) const408 const CCn3d_user_annotations * ASNDataManager::GetUserAnnotations(void) const
409 {
410     if (mimeData.NotEmpty()) {
411         if (mimeData->IsAlignstruc() && mimeData->GetAlignstruc().IsSetUser_annotations())
412             return &(mimeData->GetAlignstruc().GetUser_annotations());
413         else if (mimeData->IsAlignseq() && mimeData->GetAlignseq().IsSetUser_annotations())
414             return &(mimeData->GetAlignseq().GetUser_annotations());
415         else if (mimeData->IsStrucseq() && mimeData->GetStrucseq().IsSetUser_annotations())
416             return &(mimeData->GetStrucseq().GetUser_annotations());
417         else if (mimeData->IsStrucseqs() && mimeData->GetStrucseqs().IsSetUser_annotations())
418             return &(mimeData->GetStrucseqs().GetUser_annotations());
419         else if (mimeData->IsGeneral()) {
420             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle() &&
421                 mimeData->GetGeneral().GetSeq_align_data().GetBundle().IsSetUser_annotations())
422                 return &(mimeData->GetGeneral().GetSeq_align_data().GetBundle().GetUser_annotations());
423             else if (mimeData->GetGeneral().GetSeq_align_data().IsCdd() &&
424                      mimeData->GetGeneral().GetSeq_align_data().GetCdd().IsSetUser_annotations())
425                 return &(mimeData->GetGeneral().GetSeq_align_data().GetCdd().GetUser_annotations());
426         }
427     } else if (cddData->IsSetUser_annotations())
428         return &(cddData->GetUser_annotations());
429 
430     return NULL;
431 }
432 
SetUserAnnotations(ncbi::objects::CCn3d_user_annotations & annots)433 void ASNDataManager::SetUserAnnotations(ncbi::objects::CCn3d_user_annotations& annots)
434 {
435     if (mimeData.NotEmpty()) {
436         if (mimeData->IsAlignstruc()) mimeData->SetAlignstruc().SetUser_annotations(annots);
437         else if (mimeData->IsAlignseq()) mimeData->SetAlignseq().SetUser_annotations(annots);
438         else if (mimeData->IsStrucseq()) mimeData->SetStrucseq().SetUser_annotations(annots);
439         else if (mimeData->IsStrucseqs()) mimeData->SetStrucseqs().SetUser_annotations(annots);
440         else if (mimeData->IsGeneral()) {
441             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle())
442                 mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetUser_annotations(annots);
443             else
444                 mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetUser_annotations(annots);
445         }
446     } else
447         cddData->SetUser_annotations(annots);
448 }
449 
RemoveUserAnnotations(void)450 void ASNDataManager::RemoveUserAnnotations(void)
451 {
452     if (mimeData.NotEmpty()) {
453         if (mimeData->IsAlignstruc()) mimeData->SetAlignstruc().ResetUser_annotations();
454         else if (mimeData->IsAlignseq()) mimeData->SetAlignseq().ResetUser_annotations();
455         else if (mimeData->IsStrucseq()) mimeData->SetStrucseq().ResetUser_annotations();
456         else if (mimeData->IsStrucseqs()) mimeData->SetStrucseqs().ResetUser_annotations();
457         else if (mimeData->IsGeneral()) {
458             if (mimeData->GetGeneral().GetSeq_align_data().IsBundle())
459                 mimeData->SetGeneral().SetSeq_align_data().SetBundle().ResetUser_annotations();
460             else
461                 mimeData->SetGeneral().SetSeq_align_data().SetCdd().ResetUser_annotations();
462         }
463     } else
464         cddData->ResetUser_annotations();
465 }
466 
SetStructureAlignments(ncbi::objects::CBiostruc_annot_set * strucAligns)467 void ASNDataManager::SetStructureAlignments(ncbi::objects::CBiostruc_annot_set *strucAligns)
468 {
469     if (mimeData.NotEmpty() && mimeData->IsGeneral() && mimeData->GetGeneral().GetSeq_align_data().IsBundle()) {
470         if (strucAligns)
471             mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetStrucaligns(*strucAligns);
472         else
473             mimeData->SetGeneral().SetSeq_align_data().SetBundle().ResetStrucaligns();
474     } else if (GetInternalCDDData()) {
475         if (strucAligns)
476             GetInternalCDDData()->SetFeatures(*strucAligns);
477         else
478             GetInternalCDDData()->ResetFeatures();
479     } else
480         ERRORMSG("ASNDataManager::SetStructureAlignments() - can't add to this data type");
481     structureAlignments = strucAligns;
482 }
483 
AddBiostrucToASN(ncbi::objects::CBiostruc * biostruc)484 bool ASNDataManager::AddBiostrucToASN(ncbi::objects::CBiostruc *biostruc)
485 {
486     // if can't store add'l Biostrucs currently, try to convert to general mime if possible
487     if (!biostrucList && mimeData.NotEmpty() && !mimeData->IsGeneral())
488         ConvertMimeToGeneral();
489 
490     // add structure to list if there is one
491     if (biostrucList) {
492         biostrucList->push_back(CRef<CBiostruc>(biostruc));
493         return true;
494     }
495 
496     // if this is a CDD, we never store Biostrucs; but return true to pretend success
497     if (IsCDD()) return true;
498 
499     return false;
500 }
501 
ConvertMimeToGeneral(void)502 bool ASNDataManager::ConvertMimeToGeneral(void)
503 {
504     if (mimeData.Empty() || mimeData->IsGeneral()) {
505         ERRORMSG("ASNDataManager::ConvertMimeToGeneral() - can't convert to general mime type");
506         return false;
507     }
508 
509     CNcbi_mime_asn1 *newMime = new CNcbi_mime_asn1();
510 
511     // copy structures
512     if (biostrucList)
513         newMime->SetGeneral().SetStructures() = *biostrucList; // copy list
514     if (masterBiostruc) {
515         newMime->SetGeneral().SetStructures().push_front(CRef<CBiostruc>(masterBiostruc));
516         masterBiostruc = NULL;
517     }
518     biostrucList = (newMime->GetGeneral().GetStructures().size() > 0) ?
519         &(newMime->SetGeneral().SetStructures()) : NULL;
520 
521     // copy alignment data into bundle
522     CBundle_seqs_aligns *bundle = new CBundle_seqs_aligns();
523     newMime->SetGeneral().SetSeq_align_data().SetBundle(*bundle);
524     if (seqEntryList) {
525         bundle->SetSequences() = *seqEntryList;
526         seqEntryList = &(bundle->SetSequences());
527     }
528     if (structureAlignments)
529         bundle->SetStrucaligns(*structureAlignments);
530     if (sequenceAlignments) {
531         bundle->SetSeqaligns() = *sequenceAlignments;
532         sequenceAlignments = &(bundle->SetSeqaligns());
533     }
534 
535     // install new root mime structure
536     mimeData.Reset(newMime);
537     SetDataChanged(StructureSet::eOtherData);
538     return true;
539 }
540 
ReplaceUpdates(UpdateAlignList & newUpdates)541 void ASNDataManager::ReplaceUpdates(UpdateAlignList& newUpdates)
542 {
543     // if necessary, convert mime data into general type that has a place for imports
544     if (mimeData.NotEmpty() && !mimeData->IsGeneral() && newUpdates.size() > 0)
545         ConvertMimeToGeneral();
546 
547     // store new updates in asn data
548     if (mimeData.NotEmpty() && mimeData->IsGeneral()) {
549         if (mimeData->GetGeneral().GetSeq_align_data().IsCdd()) {
550             cddUpdates = &(mimeData->SetGeneral().SetSeq_align_data().SetCdd().SetPending());
551             *cddUpdates = newUpdates;
552         } else {
553             bundleImportsFaked = newUpdates;
554             // convert to plain imports to store in mime data (some data loss...)
555             bundleImports = &(mimeData->SetGeneral().SetSeq_align_data().SetBundle().SetImports());
556             bundleImports->clear();
557             UpdateAlignList::iterator u, ue = newUpdates.end();
558             for (u=newUpdates.begin(); u!=ue; ++u)
559                 if ((*u)->IsSetSeqannot())
560                     bundleImports->push_back(CRef < CSeq_annot > (&((*u)->SetSeqannot())));
561         }
562     } else if (cddData.NotEmpty()) {
563         cddUpdates = &(cddData->SetPending());
564         *cddUpdates = newUpdates;
565     } else if (newUpdates.size() > 0)
566         ERRORMSG("ASNDataManager::ReplaceUpdates() - can't put updates in this data type");
567 
568     SetDataChanged(StructureSet::eUpdateData);
569 }
570 
RemoveUnusedSequences(const AlignmentSet * alignmentSet,const SequenceList & updateSequences)571 void ASNDataManager::RemoveUnusedSequences(const AlignmentSet *alignmentSet,
572     const SequenceList& updateSequences)
573 {
574     if (!alignmentSet) return; // don't do this for single structures
575 
576     if (!seqEntryList) {
577         ERRORMSG("ASNDataManager::RemoveUnusedSequences() - can't find sequence list");
578         return;
579     }
580 
581     // update the asn sequences, keeping only those used in the multiple alignment and updates
582     seqEntryList->clear();
583     map < const MoleculeIdentifier *, bool > usedSeqs;
584     int nStructuredDependents = 0;
585 
586 // macro to add the sequence to the list if not already present
587 #define CONDITIONAL_ADD_SEQENTRY(seq) do { \
588     if (usedSeqs.find((seq)->identifier) == usedSeqs.end()) { \
589         seqEntryList->resize(seqEntryList->size() + 1); \
590         seqEntryList->back().Reset(new CSeq_entry); \
591         seqEntryList->back().GetObject().SetSeq((const_cast<Sequence*>(seq))->bioseqASN.GetObject()); \
592         usedSeqs[(seq)->identifier] = true; \
593     } } while (0)
594 
595     // always add master first
596     CONDITIONAL_ADD_SEQENTRY(alignmentSet->master);
597     // add from alignmentSet dependents
598     AlignmentSet::AlignmentList::const_iterator a, ae = alignmentSet->alignments.end();
599     for (a=alignmentSet->alignments.begin(); a!=ae; ++a) {
600         CONDITIONAL_ADD_SEQENTRY((*a)->dependent);
601         if ((*a)->dependent->molecule) ++nStructuredDependents;
602     }
603 
604     // add from updates
605     SequenceList::const_iterator s, se = updateSequences.end();
606     for (s=updateSequences.begin(); s!=se; ++s)
607         CONDITIONAL_ADD_SEQENTRY((*s));
608 
609     SetDataChanged(StructureSet::eSequenceData);
610 
611     // warn user if # structured dependents != # structure alignments
612 //    if (structureAlignments && nStructuredDependents !=
613 //            structureAlignments->GetFeatures().front().GetObject().GetFeatures().size())
614 //        ERRORMSG("Warning: Structure alignment list does not contain one alignment per "
615 //            "structured sequence!\nYou should recompute structure alignments before saving "
616 //            "in order to sync the lists.");
617 }
618 
WriteDataToFile(const char * filename,bool isBinary,string * err,ncbi::EFixNonPrint fixNonPrint) const619 bool ASNDataManager::WriteDataToFile(const char *filename, bool isBinary,
620     string *err, ncbi::EFixNonPrint fixNonPrint) const
621 {
622     if (mimeData.NotEmpty())
623         return WriteASNToFile(filename, mimeData.GetObject(), isBinary, err, fixNonPrint);
624     else
625         return WriteASNToFile(filename, cddData.GetObject(), isBinary, err, fixNonPrint);
626 }
627 
GetInternalCDDData(void)628 ncbi::objects::CCdd * ASNDataManager::GetInternalCDDData(void)
629 {
630     if (cddData.NotEmpty()) return cddData.GetPointer();
631     else if (mimeData.NotEmpty() && mimeData->IsGeneral() &&
632              mimeData->GetGeneral().GetSeq_align_data().IsCdd())
633         return &(mimeData->SetGeneral().SetSeq_align_data().SetCdd());
634     else
635         return NULL;
636 }
637 
GetInternalCDDData(void) const638 const ncbi::objects::CCdd * ASNDataManager::GetInternalCDDData(void) const
639 {
640     if (cddData.NotEmpty()) return cddData.GetPointer();
641     else if (mimeData.NotEmpty() && mimeData->IsGeneral() &&
642              mimeData->GetGeneral().GetSeq_align_data().IsCdd())
643         return &(mimeData->GetGeneral().GetSeq_align_data().GetCdd());
644     else
645         return NULL;
646 }
647 
IsCDD(void) const648 bool ASNDataManager::IsCDD(void) const
649 {
650     return (GetInternalCDDData() != NULL);
651 }
652 
IsCDDInMime(void) const653 bool ASNDataManager::IsCDDInMime(void) const
654 {
655     return (GetInternalCDDData() != NULL && mimeData.NotEmpty());
656 }
657 
GetCDDName(void) const658 const string& ASNDataManager::GetCDDName(void) const
659 {
660     static const string empty = "";
661     const CCdd *cdd = GetInternalCDDData();
662     if (cdd)
663         return cdd->GetName();
664     else
665         return empty;
666 }
667 
SetCDDName(const string & name)668 bool ASNDataManager::SetCDDName(const string& name)
669 {
670     CCdd *cdd = GetInternalCDDData();
671     if (!cdd || name.size() == 0) return false;
672     cdd->SetName(name);
673     SetDataChanged(StructureSet::eCDDData);
674     return true;
675 }
676 
GetCDDDescription(void) const677 const string& ASNDataManager::GetCDDDescription(void) const
678 {
679     static const string empty = "";
680     const CCdd *cdd = GetInternalCDDData();
681     if (!cdd) return empty;
682 
683     // find first 'comment' in Cdd-descr-set, assume this is the "long description"
684     if (!cdd->IsSetDescription() || cdd->GetDescription().Get().size() == 0) return empty;
685     CCdd_descr_set::Tdata::const_iterator d, de = cdd->GetDescription().Get().end();
686     for (d=cdd->GetDescription().Get().begin(); d!=de; ++d)
687         if ((*d)->IsComment())
688             return (*d)->GetComment();
689 
690     return empty;
691 }
692 
SetCDDDescription(const string & descr)693 bool ASNDataManager::SetCDDDescription(const string& descr)
694 {
695     CCdd *cdd = GetInternalCDDData();
696     if (!cdd) return false;
697 
698     if (cdd->IsSetDescription() && cdd->GetDescription().Get().size() > 0) {
699         // find first 'comment' in Cdd-descr-set, assume this is the "long description"
700         CCdd_descr_set::Tdata::iterator d, de = cdd->SetDescription().Set().end();
701         for (d=cdd->SetDescription().Set().begin(); d!=de; ++d) {
702             if ((*d)->IsComment()) {
703                 if ((*d)->GetComment() != descr) {
704                     (*d)->SetComment(descr);
705                     SetDataChanged(StructureSet::eCDDData);
706                 }
707                 return true;
708             }
709         }
710     }
711 
712     // add new comment if not yet present
713     CRef < CCdd_descr > comment(new CCdd_descr);
714     comment->SetComment(descr);
715     cdd->SetDescription().Set().push_front(comment);
716     SetDataChanged(StructureSet::eCDDData);
717     return true;
718 }
719 
GetCDDNotes(TextLines * lines) const720 bool ASNDataManager::GetCDDNotes(TextLines *lines) const
721 {
722     const CCdd *cdd = GetInternalCDDData();
723     if (!lines || !cdd) return false;
724     lines->clear();
725 
726     if (!cdd->IsSetDescription() || cdd->GetDescription().Get().size() == 0)
727         return true;
728 
729     // find scrapbook item
730     CCdd_descr_set::Tdata::const_iterator d, de = cdd->GetDescription().Get().end();
731     for (d=cdd->GetDescription().Get().begin(); d!=de; ++d) {
732         if ((*d)->IsScrapbook()) {
733 
734             // fill out lines from scrapbook string list
735             lines->resize((*d)->GetScrapbook().size());
736             CCdd_descr::TScrapbook::const_iterator l, le = (*d)->GetScrapbook().end();
737             int i = 0;
738             for (l=(*d)->GetScrapbook().begin(); l!=le; ++l)
739                 (*lines)[i++] = *l;
740             return true;
741         }
742     }
743     return true;
744 }
745 
SetCDDNotes(const TextLines & lines)746 bool ASNDataManager::SetCDDNotes(const TextLines& lines)
747 {
748     CCdd *cdd = GetInternalCDDData();
749     if (!cdd) return false;
750 
751     CCdd_descr::TScrapbook *scrapbook = NULL;
752 
753     // find an existing scrapbook item
754     if (cdd->IsSetDescription()) {
755         CCdd_descr_set::Tdata::iterator d, de = cdd->SetDescription().Set().end();
756         for (d=cdd->SetDescription().Set().begin(); d!=de; ++d) {
757             if ((*d)->IsScrapbook()) {
758                 if (lines.size() == 0) {
759                     cdd->SetDescription().Set().erase(d);   // if empty, remove scrapbook item
760                     SetDataChanged(StructureSet::eCDDData);
761                     TRACEMSG("removed scrapbook");
762                 } else
763                     scrapbook = &((*d)->SetScrapbook());
764                 break;
765             }
766         }
767     }
768     if (lines.size() == 0) return true;
769 
770     // create a scrapbook item if doesn't exist already
771     if (!scrapbook) {
772         CRef < CCdd_descr > descr(new CCdd_descr());
773         scrapbook = &(descr->SetScrapbook());
774         cdd->SetDescription().Set().push_back(descr);
775     }
776 
777     // fill out scrapbook lines
778     scrapbook->clear();
779     for (unsigned int i=0; i<lines.size(); ++i)
780         scrapbook->push_back(lines[i]);
781     SetDataChanged(StructureSet::eCDDData);
782 
783     return true;
784 }
785 
GetCDDDescrSet(void)786 ncbi::objects::CCdd_descr_set * ASNDataManager::GetCDDDescrSet(void)
787 {
788     CCdd *cdd = GetInternalCDDData();
789     if (cdd) {
790         // make a new descr set if not present
791         if (!cdd->IsSetDescription()) {
792             CRef < CCdd_descr_set > ref(new CCdd_descr_set());
793             cdd->SetDescription(*ref);
794         }
795         return &(cdd->SetDescription());
796     } else
797         return NULL;
798 }
799 
GetCDDAnnotSet(void)800 ncbi::objects::CAlign_annot_set * ASNDataManager::GetCDDAnnotSet(void)
801 {
802     CCdd *cdd = GetInternalCDDData();
803     if (cdd) {
804         // make a new annot set if not present
805         if (!cdd->IsSetAlignannot()) {
806 			CRef < CAlign_annot_set > ref(new CAlign_annot_set());
807             cdd->SetAlignannot(*ref);
808         }
809         return &(cdd->SetAlignannot());
810     } else
811         return NULL;
812 }
813 
GetCDDMaster3d(void) const814 const ncbi::objects::CSeq_id * ASNDataManager::GetCDDMaster3d(void) const
815 {
816     const CCdd *cdd = GetInternalCDDData();
817     if (cdd && cdd->IsSetMaster3d() && cdd->GetMaster3d().size() > 0)
818         return cdd->GetMaster3d().front().GetPointer(); // just return the first one...
819     else
820         return NULL;
821 }
822 
AddReject(ncbi::objects::CReject_id * reject)823 void ASNDataManager::AddReject(ncbi::objects::CReject_id *reject)
824 {
825     CCdd *cdd = GetInternalCDDData();
826     if (!cdd) return;
827 
828     cdd->SetRejects().push_back(CRef < CReject_id > (reject));
829     dataChanged |= StructureSet::eCDDData;
830 }
831 
GetRejects(void) const832 const StructureSet::RejectList * ASNDataManager::GetRejects(void) const
833 {
834     const CCdd *cdd = GetInternalCDDData();
835     if (!cdd || !cdd->IsSetRejects())
836         return NULL;
837     return &(cdd->GetRejects());
838 }
839 
840 // the following three Check... functions are taken from CDTree2
841 
CheckOneDenDiag(CRef<CDense_diag> & DenDiag,string & Str)842 bool CheckOneDenDiag(CRef<CDense_diag>& DenDiag, string& Str) {
843 //---------------------------------------------------------------------------
844 // check integrity of DenDiag.
845 //---------------------------------------------------------------------------
846     int  Start1, Start2, Len, Dim;
847     char buf[1024];
848     bool RetVal = true;
849 
850     // check that Dim of this dense-diag is exactly 2
851     Dim = DenDiag->GetDim();
852     if (Dim != 2) {
853         sprintf(buf, "Dense-diag Dim = %d. It should always be exactly 2.\n", Dim);
854         RetVal = false;
855     }
856 
857     // check that Len of this dense-diag is at least 1
858     Len = DenDiag->GetLen();
859     if (Len < 0) {
860         sprintf(buf, "Dense-diag Len = %d. It should always be non-negative.\n", Len);
861         RetVal = false;
862     }
863 
864     // check that Start of first row is sensible.
865     Start1 = DenDiag->GetStarts().front();
866     if (Start1 < 0) {
867         sprintf(buf, "Dense-diag has 1st row Start %d. It should always be non-negative.\n", Start1);
868         RetVal = false;
869     }
870 
871     // check that Start of second row is sensible.
872     Start2 = DenDiag->GetStarts().back();
873     if (Start2 < 0) {
874         sprintf(buf, "Dense-diag has 2nd row start %d. It should always be non-negative.\n", Start2);
875         RetVal = false;
876     }
877 
878     if (!RetVal) {
879         Str += buf;
880     }
881     return(RetVal);
882 }
883 
CheckTwoDenDiags(CRef<CDense_diag> & DenDiag1,CRef<CDense_diag> & DenDiag2,string & Str)884 bool CheckTwoDenDiags(CRef<CDense_diag>& DenDiag1, CRef<CDense_diag>& DenDiag2, string& Str) {
885 //---------------------------------------------------------------------------
886 // check that DenDiag2 follows DenDiag1.
887 //---------------------------------------------------------------------------
888     int  Start11, Start12, Start21, Start22, Len;
889     char buf[1024];
890     bool RetVal = true;
891 
892     // get starts for first den-diag, and get its len
893     Start11 = DenDiag1->GetStarts().front();
894     Start12 = DenDiag1->GetStarts().back();
895     Len = DenDiag1->GetLen();
896 
897     // get starts for second den-diag
898     Start21 = DenDiag2->GetStarts().front();
899     Start22 = DenDiag2->GetStarts().back();
900 
901     // make sure starts for second den-diag follow starts for first
902     if (Start21 < (Start11 + Len)) {
903         sprintf(buf, "Dense-diag has 1st row Start %d, Len %d. Next Dense-diag has Start %d.\n", Start11, Len, Start21);
904         RetVal = false;
905     }
906 
907     if (Start22 < (Start12 + Len)) {
908         sprintf(buf, "Dense-diag has 2nd row Start %d, Len %d. Next Dense-diag has Start %d.\n", Start12, Len, Start22);
909         RetVal = false;
910     }
911 
912     if (!RetVal) {
913         Str += buf;
914     }
915     return(RetVal);
916 }
917 
CheckOneAlignment(const CRef<CSeq_align> & SeqAlign,string & Str)918 bool CheckOneAlignment(const CRef<CSeq_align>& SeqAlign, string& Str) {
919 //---------------------------------------------------------------------------
920 // check integrity of one aligment
921 //---------------------------------------------------------------------------
922     list< CRef< CDense_diag > >            DenDiags;
923     list< CRef< CDense_diag > >::iterator  dd_iter;
924           CRef< CDense_diag >              DenDiag1, DenDiag2;
925     bool  RetVal = true;
926 
927     // if alignment has no dense-diags go to next alignment
928     if (!SeqAlign->GetSegs().IsDendiag()) return(RetVal);
929 
930     // get den-diags of alignment
931     DenDiags = SeqAlign->GetSegs().GetDendiag();
932 
933     // get first den-diag
934     dd_iter = DenDiags.begin();
935     DenDiag1 = *dd_iter;
936 
937     // check integrity of first den-diag
938     if (!CheckOneDenDiag(DenDiag1, Str)) RetVal = false;
939 
940     // handle case when there's just one den-diag in the alignment
941     if (dd_iter == DenDiags.end()) return(RetVal);
942     dd_iter++;
943 
944     // loop through the den-diags.  make sure we're ascending.
945     for (; dd_iter != DenDiags.end(); dd_iter++) {
946         // get next den-diag
947         DenDiag2 = *dd_iter;
948         // check integrity of this den-diag
949         if (!CheckOneDenDiag(DenDiag2, Str)) RetVal = false;
950         // check that this den-diag is later in the sequence than preceeding den-diag
951         if (!CheckTwoDenDiags(DenDiag1, DenDiag2, Str)) RetVal = false;
952         DenDiag1 = DenDiag2;
953     }
954     return(RetVal);
955 }
956 
MonitorAlignments(void) const957 bool ASNDataManager::MonitorAlignments(void) const
958 {
959 #ifndef _DEBUG
960     return true;
961 
962 #else
963 //  ... for development only...
964     bool okay = true;
965     string messages;
966     char buf[1024];
967 
968     // check regular alignments
969     const SeqAnnotList *seqAnnots = GetSequenceAlignments();
970     if (seqAnnots) {
971         SeqAnnotList::const_iterator a, ae = seqAnnots->end();
972         for (a=seqAnnots->begin(); a!=ae; ++a) {
973             if ((*a)->GetData().IsAlign()) {
974                 CSeq_annot::C_Data::TAlign::const_iterator s, se = (*a)->GetData().GetAlign().end();
975                 int n = 1;
976                 for (s=(*a)->GetData().GetAlign().begin(); s!=se; ++s, ++n) {
977                     if (!CheckOneAlignment(*s, messages)) {
978                         okay = false;
979                         sprintf(buf, "Normal Alignment #%i\n\n", n);
980                         messages += buf;
981                     }
982                 }
983             }
984         }
985     }
986 
987     // check update alignments
988     const UpdateAlignList *updates = GetUpdates();
989     if (updates) {
990         UpdateAlignList::const_iterator u, ue = updates->end();
991         for (u=updates->begin(); u!=ue; ++u) {
992             if ((*u)->IsSetSeqannot() && (*u)->GetSeqannot().GetData().IsAlign()) {
993                 CSeq_annot::C_Data::TAlign::const_iterator s, se = (*u)->GetSeqannot().GetData().GetAlign().end();
994                 int n = 1;
995                 for (s=(*u)->GetSeqannot().GetData().GetAlign().begin(); s!=se; ++s, ++n) {
996                     if (!CheckOneAlignment(*s, messages)) {
997                         okay = false;
998                         sprintf(buf, "Pending Alignment #%i\n\n", n);
999                         messages += buf;
1000                     }
1001                 }
1002             }
1003         }
1004     }
1005 
1006     if (okay)
1007         TRACEMSG("MonitorAlignments() succeeded");
1008     else {
1009         ERRORMSG("MonitorAlignments() found errors, see log for details; please copy&paste and send a complete report to cdt-swg");
1010         WARNINGMSG("MonitorAlignments() found errors:\n\n" << messages);
1011     }
1012     return okay;
1013 #endif
1014 }
1015 
CreateMimeFromBiostruc(const string & filename,EModel_type model)1016 CNcbi_mime_asn1 * CreateMimeFromBiostruc(const string& filename, EModel_type model)
1017 {
1018     // read Biostruc
1019     CRef < CBiostruc > biostruc(new CBiostruc());
1020     string err;
1021     SetDiagPostLevel(eDiag_Fatal); // ignore all but Fatal errors while reading data
1022     bool okay = (ReadASNFromFile(filename.c_str(), biostruc.GetPointer(), true, &err) ||
1023                  ReadASNFromFile(filename.c_str(), biostruc.GetPointer(), false, &err));
1024     SetDiagPostLevel(eDiag_Info);
1025     if (!okay) {
1026         ERRORMSG("This file is not a valid Biostruc");
1027         TRACEMSG("err: " << err);
1028         return NULL;
1029     }
1030 
1031     return CreateMimeFromBiostruc(biostruc, model);
1032 }
1033 
CreateMimeFromBiostruc(CRef<CBiostruc> & biostruc,EModel_type model)1034 CNcbi_mime_asn1 * CreateMimeFromBiostruc(CRef < CBiostruc >& biostruc, EModel_type model)
1035 {
1036     // remove all but desired model coordinates
1037     list < CRef < CBiostruc_model > > desiredModels;
1038     CBiostruc::TModel::const_iterator m, me = biostruc->GetModel().end();
1039     for (m=biostruc->GetModel().begin(); m!=me; ++m) {
1040         if ((*m)->GetType() == model)
1041             desiredModels.push_back(*m);
1042     }
1043     if (desiredModels.size() == 0) {
1044         ERRORMSG("Ack! There's no appropriate model in this Biostruc");
1045         return NULL;
1046     }
1047     biostruc->ResetModel();
1048     biostruc->SetModel() = desiredModels;
1049 
1050     // package Biostruc inside a mime object
1051     CRef < CNcbi_mime_asn1 > mime(new CNcbi_mime_asn1());
1052     CRef < CBiostruc_seq > strucseq(new CBiostruc_seq());
1053     mime->SetStrucseq(*strucseq);
1054     strucseq->SetStructure(*biostruc);
1055 
1056     // get list of gi's to import
1057     vector < int > gis;
1058     CBiostruc_graph::TMolecule_graphs::const_iterator g,
1059         ge = biostruc->GetChemical_graph().GetMolecule_graphs().end();
1060     for (g=biostruc->GetChemical_graph().GetMolecule_graphs().begin(); g!=ge; ++g) {
1061         if ((*g)->IsSetSeq_id() && (*g)->GetSeq_id().IsGi())
1062             gis.push_back((*g)->GetSeq_id().GetGi());
1063     }
1064 
1065     // fetch sequences and store in mime
1066     if (gis.size() > 0) {
1067         CRef < CSeq_entry > seqs(new CSeq_entry());
1068         strucseq->SetSequences().push_back(seqs);
1069         CRef < CBioseq_set > seqset(new CBioseq_set());
1070         seqs->SetSet(*seqset);
1071         for (unsigned int i=0; i<gis.size(); ++i) {
1072             CRef < CBioseq > bioseq = FetchSequenceViaHTTP(NStr::IntToString(gis[i]));
1073             if (bioseq.NotEmpty()) {
1074                 CRef < CSeq_entry > seqentry(new CSeq_entry());
1075                 seqentry->SetSeq(*bioseq);
1076                 seqset->SetSeq_set().push_back(seqentry);
1077             } else {
1078                 ERRORMSG("Failed to retrieve all Bioseqs");
1079                 return NULL;
1080             }
1081         }
1082     } else
1083         WARNINGMSG("Can't find any sequence gi identifiers in this Biostruc");
1084 
1085     return mime.Release();
1086 }
1087 
1088 END_SCOPE(Cn3D)
1089