1 /* ===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  */
25 
26 #include <ngs-bam/ngs-bam.hpp>
27 #include "bam.hpp"
28 
29 #include <ngs/ReadCollection.hpp>
30 #include <ngs/adapter/ReadCollectionItf.hpp>
31 #include <ngs/adapter/AlignmentItf.hpp>
32 #include <ngs/adapter/ReferenceItf.hpp>
33 #include <ngs/adapter/StringItf.hpp>
34 
35 class ReadCollection : public ngs_adapt::ReadCollectionItf
36 {
37     class Alignment;
38     class AlignmentNone;
39     class AlignmentSlice;
40     class Reference;
41 
42     BAMFile file;
43     std::string const path;         /* path used to open the BAM file       */
44 public:
ReadCollection(std::string const & filepath)45     ReadCollection(std::string const &filepath)
46     : path(filepath)
47     , file(filepath)
48     {};
49 
50     ngs_adapt::StringItf *getName() const;
51     ngs_adapt::ReadGroupItf *getReadGroups() const;
52     bool hasReadGroup(char const spec[]) const;
53     ngs_adapt::ReadGroupItf *getReadGroup(char const spec[]) const;
54     ngs_adapt::ReferenceItf *getReferences() const;
55     bool hasReference(char const spec[]) const;
56     ngs_adapt::ReferenceItf *getReference(char const spec[]) const;
57     ngs_adapt::AlignmentItf *getAlignment(char const spec[]) const;
58     ngs_adapt::AlignmentItf *getAlignments(bool const want_primary,
59                                            bool const want_secondary) const;
60     uint64_t getAlignmentCount(bool const want_primary,
61                                bool const want_secondary) const;
62     ngs_adapt::AlignmentItf *getAlignmentRange(uint64_t const first,
63                                                uint64_t const count,
64                                                bool const want_primary,
65                                                bool const want_secondary ) const;
66     uint64_t getReadCount(bool const want_full,
67                           bool const want_partial,
68                           bool const want_unaligned) const;
69     ngs_adapt::ReadItf *getRead(char const spec[]) const;
70     ngs_adapt::ReadItf *getReads(bool const want_full,
71                                  bool const want_partial,
72                                  bool const want_unaligned) const;
73     ngs_adapt::ReadItf *getReadRange(uint64_t const first,
74                                      uint64_t const count,
75                                      bool const want_full,
76                                      bool const want_partial,
77                                      bool const want_unaligned) const;
78 
Seek(BAMFilePosType const new_pos)79     void Seek(BAMFilePosType const new_pos) {
80     	file.Seek(new_pos.fpos(), new_pos.bpos());
81     }
ReadBAMRecord()82     BAMRecord const *ReadBAMRecord() {
83         return file.Read();
84     }
getRefInfo(unsigned const i) const85     HeaderRefInfo const &getRefInfo(unsigned const i) const {
86         return file.getRefInfo(i);
87     }
88 };
89 
90 // base class for the Alignment types
91 // defines the default behavior of the Alignment types
92 // by design, this class doesn't actually do anything but throw errors
93 // it is the type that is returned when there can't be any alignments
94 // for example, if want_primary and want_secondary are both false
95 class ReadCollection::AlignmentNone : public ngs_adapt::AlignmentItf
96 {
getCigar(bool const clipped,char const OPCODE[]) const97     virtual ngs_adapt::StringItf *getCigar(bool const clipped, char const OPCODE[]) const {
98         throw std::runtime_error("no rows");
99     }
100 public:
getFragmentId() const101     ngs_adapt::StringItf *getFragmentId() const {
102         throw std::runtime_error("not available");
103     }
getFragmentBases(uint64_t offset,uint64_t length) const104     ngs_adapt::StringItf *getFragmentBases(uint64_t offset, uint64_t length) const {
105         throw std::runtime_error("no rows");
106     }
getFragmentQualities(uint64_t offset,uint64_t length) const107     ngs_adapt::StringItf *getFragmentQualities(uint64_t offset, uint64_t length) const {
108         throw std::runtime_error("no rows");
109     }
getAlignmentId() const110     ngs_adapt::StringItf *getAlignmentId() const {
111         throw std::runtime_error("not available");
112     }
getReferenceSpec() const113     ngs_adapt::StringItf *getReferenceSpec() const {
114         throw std::runtime_error("no rows");
115     }
getMappingQuality() const116     int32_t getMappingQuality() const {
117         throw std::runtime_error("no rows");
118     }
getReferenceBases() const119     ngs_adapt::StringItf *getReferenceBases() const {
120         throw std::runtime_error("not available");
121     }
getReadGroup() const122     ngs_adapt::StringItf *getReadGroup() const {
123         throw std::runtime_error("no rows");
124     }
getReadId() const125     ngs_adapt::StringItf *getReadId() const {
126         throw std::runtime_error("no rows");
127     }
getClippedFragmentBases() const128     ngs_adapt::StringItf *getClippedFragmentBases() const {
129         throw std::runtime_error("not available");
130     }
getClippedFragmentQualities() const131     ngs_adapt::StringItf *getClippedFragmentQualities() const {
132         throw std::runtime_error("not available");
133     }
getAlignedFragmentBases() const134     ngs_adapt::StringItf *getAlignedFragmentBases() const {
135         throw std::runtime_error("not available");
136     }
getAlignedFragmentQualities() const137     ngs_adapt::StringItf *getAlignedFragmentQualities() const {
138         throw std::runtime_error("not available");
139     }
isPrimary() const140     bool isPrimary() const {
141         throw std::runtime_error("no rows");
142     }
getAlignmentPosition() const143     int64_t getAlignmentPosition() const {
144         throw std::runtime_error("no rows");
145     }
getReferencePositionProjectionRange(int64_t ref_pos) const146     uint64_t getReferencePositionProjectionRange ( int64_t ref_pos ) const {
147         throw std::runtime_error("no rows");
148     }
getAlignmentLength() const149     uint64_t getAlignmentLength() const {
150         throw std::runtime_error("no rows");
151     }
getShortCigar(bool clipped) const152     ngs_adapt::StringItf *getShortCigar(bool clipped) const {
153         return getCigar(clipped, "MIDNSHPMM???????");
154     }
getLongCigar(bool clipped) const155     ngs_adapt::StringItf *getLongCigar(bool clipped) const {
156         return getCigar(clipped, "MIDNSHP=X???????");
157     }
getRNAOrientation() const158     char getRNAOrientation () const {
159         throw std::runtime_error("no rows");
160     }
getIsReversedOrientation() const161     bool getIsReversedOrientation() const {
162         throw std::runtime_error("no rows");
163     }
getSoftClip(uint32_t edge) const164     int32_t getSoftClip(uint32_t edge) const {
165         throw std::runtime_error("not available");
166     }
getTemplateLength() const167     uint64_t getTemplateLength() const {
168         throw std::runtime_error("no rows");
169     }
hasMate() const170     bool hasMate() const {
171         throw std::runtime_error("no rows");
172     }
getMateAlignmentId() const173     ngs_adapt::StringItf *getMateAlignmentId() const {
174         throw std::runtime_error("not available");
175     }
getMateAlignment() const176     ngs_adapt::AlignmentItf *getMateAlignment() const {
177         throw std::runtime_error("not available");
178     }
getMateReferenceSpec() const179     ngs_adapt::StringItf *getMateReferenceSpec() const {
180         throw std::runtime_error("no rows");
181     }
getMateIsReversedOrientation() const182     bool getMateIsReversedOrientation() const {
183         throw std::runtime_error("no rows");
184     }
nextAlignment()185     bool nextAlignment() {
186         return false;
187     }
nextFragment()188     bool nextFragment() {
189         throw std::runtime_error("not available");
190     }
191 };
192 
193 class ReadCollection::Alignment : public ReadCollection::AlignmentNone
194 {
195     mutable std::string seqBuffer;
196     mutable std::string qualBuffer;
197     mutable std::string cigarBuffer;
198 protected:
199     ReadCollection *parent;
200     BAMRecord const *current;
201     bool want_primary;
202     bool want_secondary;
203 
204     ngs_adapt::StringItf *getCigar(bool const clipped, char const OPCODE[]) const;
205 
shouldSkip() const206     bool shouldSkip() const {
207         int const flag = current->flag();
208 
209         if ((flag & 0x0004) != 0)
210             return true;
211 
212         if ((flag & 0x0900) == 0 && !want_primary)
213             return true;
214 
215         if ((flag & 0x0900) != 0 && !want_secondary)
216             return true;
217 
218         return false;
219     }
220 
221 public:
Alignment(ReadCollection const * Parent,bool WantPrimary,bool WantSecondary)222     Alignment(ReadCollection const *Parent, bool WantPrimary, bool WantSecondary) {
223         parent = static_cast<ReadCollection *>(Parent->Duplicate());
224         want_primary = WantPrimary;
225         want_secondary = WantSecondary;
226         current = 0;
227     }
~Alignment()228     virtual ~Alignment() {
229         if (current)
230             delete current;
231         parent->Release();
232     }
233 
234     ngs_adapt::StringItf *getFragmentBases(uint64_t offset, uint64_t length) const;
235     ngs_adapt::StringItf *getFragmentQualities(uint64_t offset, uint64_t length) const;
236     ngs_adapt::StringItf *getReferenceSpec() const;
237     int32_t getMappingQuality() const;
238     ngs_adapt::StringItf *getReadGroup() const;
239     ngs_adapt::StringItf *getReadId() const;
240     bool isPrimary() const;
241     int64_t getAlignmentPosition() const;
242     uint64_t getAlignmentLength() const;
243     bool getIsReversedOrientation() const;
244     uint64_t getTemplateLength() const;
245     bool hasMate() const;
246     ngs_adapt::StringItf *getMateReferenceSpec() const;
247     bool getMateIsReversedOrientation() const;
248     bool nextAlignment();
249 };
250 
251 class ReadCollection::AlignmentSlice : public ReadCollection::Alignment
252 {
253     unsigned refID;
254     unsigned beg;
255     unsigned end;
256     BAMFilePosTypeList const slice;
257     BAMFilePosTypeList::const_iterator cur;
258 public:
AlignmentSlice(ReadCollection const * Parent,bool const WantPrimary,bool const WantSecondary,BAMFilePosTypeList const & Slice,unsigned const Beg,unsigned const End)259     AlignmentSlice(ReadCollection const *Parent,
260                    bool const WantPrimary,
261                    bool const WantSecondary,
262                    BAMFilePosTypeList const &Slice,
263                    unsigned const Beg,
264                    unsigned const End)
265     : Alignment(Parent, WantPrimary, WantSecondary)
266     , slice(Slice)
267     , beg(Beg)
268     , end(End)
269     , cur(Slice.begin())
270     {
271         parent->Seek(*cur++);
272     }
273 
nextAlignment()274     bool nextAlignment() {
275         for ( ; ; ) {
276             if (!Alignment::nextAlignment())
277                 return false;
278             if (current->isSelfMapped()) {
279                 unsigned const POS   = current->pos();
280                 unsigned const REFID = current->refID();
281 
282                 if (REFID != refID || POS >= end)
283                     return false;
284 
285                 unsigned const REFLEN = current->refLen();
286                 if (POS + REFLEN > beg)
287                     return true;
288             }
289         }
290     }
291 };
292 
293 class ReadCollection::Reference : public ngs_adapt::ReferenceItf
294 {
295     ReadCollection *parent;
296     unsigned cur;
297     unsigned max;
298     int state;
299 
300 public:
Reference(ReadCollection const * const Parent,unsigned const current,unsigned const references,int const initState)301     Reference(ReadCollection const *const Parent,
302               unsigned const current,
303               unsigned const references,
304               int const initState)
305     : parent(static_cast<ReadCollection *>(Parent->Duplicate()))
306     , cur(current)
307     , max(references)
308     , state(initState)
309     {}
310 
~Reference()311     ~Reference() {
312         parent->Release();
313     }
314 
getCommonName() const315     ngs_adapt::StringItf *getCommonName() const {
316         if (state == 2)
317             throw std::runtime_error("no current row");
318 
319         HeaderRefInfo const &ri = parent->getRefInfo(cur);
320         std::string const &RNAME = ri.getName();
321 
322         return new ngs_adapt::StringItf(RNAME.data(), RNAME.size());
323     }
getCanonicalName() const324     ngs_adapt::StringItf *getCanonicalName() const {
325         throw std::runtime_error("not available");
326     }
327     // TODO: rename to isCircular
getIsCircular() const328     bool getIsCircular() const {
329         throw std::runtime_error("not available");
330     }
getIsLocal() const331      bool getIsLocal () const {
332         throw std::runtime_error("not available");
333     }
getLength() const334     uint64_t getLength() const {
335         if (state == 2)
336             throw std::runtime_error("no current row");
337 
338         HeaderRefInfo const &ri = parent->getRefInfo(cur);
339 
340         return ri.getLength();
341     }
getReferenceBases(uint64_t const offset,uint64_t const length) const342     ngs_adapt::StringItf *getReferenceBases(uint64_t const offset, uint64_t const length) const {
343         throw std::runtime_error("not available");
344     }
getReferenceChunk(uint64_t const offset,uint64_t const length) const345     ngs_adapt::StringItf *getReferenceChunk(uint64_t const offset, uint64_t const length) const {
346         throw std::runtime_error("not available");
347     }
getAlignmentCount(bool wants_primary,bool wants_secondary) const348     uint64_t getAlignmentCount ( bool wants_primary, bool wants_secondary ) const {
349         throw std::runtime_error("not available");
350     }
getAlignment(char const id[]) const351     ngs_adapt::AlignmentItf *getAlignment(char const id[]) const {
352         throw std::runtime_error("not available");
353     }
getAlignments(bool const want_primary,bool const want_secondary) const354     ngs_adapt::AlignmentItf *getAlignments(bool const want_primary, bool const want_secondary) const {
355         return getAlignmentSlice(0, getLength(), want_primary, want_secondary);
356     }
getAlignmentSlice(int64_t const Start,uint64_t const length,bool const want_primary,bool const want_secondary) const357     ngs_adapt::AlignmentItf *getAlignmentSlice(int64_t const Start, uint64_t const length, bool const want_primary, bool const want_secondary) const {
358         if (state == 2)
359             throw std::runtime_error("no current row");
360 
361         HeaderRefInfo const &ri = parent->getRefInfo(cur);
362         unsigned const len = ri.getLength();
363         if (Start >= len)
364             return new ReadCollection::AlignmentNone();
365 
366         unsigned const start = Start < 0 ? 0 : Start;
367         uint64_t const End = (Start < 0 ? 0 : Start) + length;
368         unsigned const end = End > len ? len : End;
369         BAMFilePosTypeList const &slice = ri.slice(start, end);
370 
371         if (slice.size() == 0)
372             return new ReadCollection::AlignmentNone();
373 
374         return new ReadCollection::AlignmentSlice(parent, want_primary, want_secondary,
375                                                   slice, start, end);
376     }
getFilteredAlignmentSlice(int64_t start,uint64_t length,uint32_t flags,int32_t map_qual) const377     ngs_adapt::AlignmentItf * getFilteredAlignmentSlice ( int64_t start, uint64_t length, uint32_t flags, int32_t map_qual ) const {
378         throw std::runtime_error("not available");
379     }
getPileups(bool const want_primary,bool const want_secondary) const380     ngs_adapt::PileupItf *getPileups(bool const want_primary, bool const want_secondary) const {
381         throw std::runtime_error("not available");
382     }
getFilteredPileups(uint32_t flags,int32_t map_qual) const383     ngs_adapt::PileupItf *getFilteredPileups(uint32_t flags, int32_t map_qual) const {
384         throw std::runtime_error("not available");
385     }
getPileupSlice(int64_t const start,uint64_t const length,bool const want_primary,bool const want_secondary) const386     ngs_adapt::PileupItf *getPileupSlice(int64_t const start, uint64_t const length, bool const want_primary, bool const want_secondary) const {
387         throw std::runtime_error("not available");
388     }
getFilteredPileupSlice(int64_t const start,uint64_t const length,uint32_t flags,int32_t map_qual) const389     ngs_adapt::PileupItf *getFilteredPileupSlice(int64_t const start, uint64_t const length, uint32_t flags, int32_t map_qual) const {
390         throw std::runtime_error("not available");
391     }
nextReference()392     bool nextReference() {
393         switch (state) {
394             case 0:
395                 if (cur < max) {
396                     state = 1;
397                     return true;
398                 }
399                 else {
400                     state = 2;
401                     return false;
402                 }
403             case 1:
404                 ++cur;
405                 if (cur < max)
406                     return true;
407                 state = 2;
408             case 2:
409                 return false;
410             default:
411                 throw std::runtime_error("no more rows available");
412         }
413     }
414 };
415 
getName() const416 ngs_adapt::StringItf *ReadCollection::getName() const
417 {
418     unsigned const sep = path.rfind('/');
419 
420     if (sep == path.npos)
421         return new ngs_adapt::StringItf(path.data(), path.size());
422     else {
423         char const *name = path.data() + sep + 1;
424         unsigned const len = path.size() - sep - 1;
425         return new ngs_adapt::StringItf(name, len);
426     }
427 }
428 
getReadGroups() const429 ngs_adapt::ReadGroupItf *ReadCollection::getReadGroups() const
430 {
431     throw std::logic_error("unimplemented");
432 }
433 
hasReadGroup(char const spec[]) const434 bool ReadCollection::hasReadGroup(char const spec[]) const
435 {
436     return false;
437 }
438 
getReadGroup(char const spec[]) const439 ngs_adapt::ReadGroupItf *ReadCollection::getReadGroup(char const spec[]) const
440 {
441     throw std::logic_error("unimplemented");
442 }
443 
getReferences() const444 ngs_adapt::ReferenceItf *ReadCollection::getReferences() const
445 {
446     return new Reference(this, 0, file.countOfReferences(), 0);
447 }
448 
hasReference(char const spec[]) const449 bool ReadCollection::hasReference(char const spec[]) const
450 {
451     int const i = file.getReferenceIndexByName(spec);
452     return i >= 0;
453 }
454 
getReference(char const spec[]) const455 ngs_adapt::ReferenceItf *ReadCollection::getReference(char const spec[]) const
456 {
457     int const i = file.getReferenceIndexByName(spec);
458 
459     if (i < 0)
460         return NULL;
461     else
462         return new Reference(this, i, 0, 3);
463 }
464 
getAlignment(char const spec[]) const465 ngs_adapt::AlignmentItf *ReadCollection::getAlignment(char const spec[]) const
466 {
467     throw std::logic_error("unimplemented");
468 }
469 
getAlignments(bool const want_primary,bool const want_secondary) const470 ngs_adapt::AlignmentItf *ReadCollection::getAlignments(bool const want_primary,
471                                                        bool const want_secondary) const
472 {
473     if (!want_secondary && !want_primary)
474         return new AlignmentNone();
475     const_cast<BAMFile *>(&file)->Rewind();
476     return new Alignment(this, want_primary, want_secondary);
477 }
478 
getAlignmentCount(bool const want_primary,bool const want_secondary) const479 uint64_t ReadCollection::getAlignmentCount(bool const want_primary,
480                                            bool const want_secondary) const
481 {
482     throw std::logic_error("unimplemented");
483 }
484 
getAlignmentRange(uint64_t const first,uint64_t const count,bool const want_primary,bool const want_secondary) const485 ngs_adapt::AlignmentItf *ReadCollection::getAlignmentRange(uint64_t const first,
486                                                            uint64_t const count,
487                                                            bool const want_primary,
488                                                            bool const want_secondary ) const
489 {
490     throw std::logic_error("unimplemented");
491 }
492 
getReadCount(bool const want_full,bool const want_partial,bool const want_unaligned) const493 uint64_t ReadCollection::getReadCount(bool const want_full,
494                                       bool const want_partial,
495                                       bool const want_unaligned) const
496 {
497     throw std::logic_error("unimplemented");
498 }
499 
getRead(char const spec[]) const500 ngs_adapt::ReadItf *ReadCollection::getRead(char const spec[]) const
501 {
502     throw std::logic_error("unimplemented");
503 }
504 
getReads(bool const want_full,bool const want_partial,bool const want_unaligned) const505 ngs_adapt::ReadItf *ReadCollection::getReads(bool const want_full,
506                                              bool const want_partial,
507                                              bool const want_unaligned) const
508 {
509     throw std::logic_error("unimplemented");
510 }
511 
getReadRange(uint64_t const first,uint64_t const count,bool const want_full,bool const want_partial,bool const want_unaligned) const512 ngs_adapt::ReadItf *ReadCollection::getReadRange(uint64_t const first,
513                                                  uint64_t const count,
514                                                  bool const want_full,
515                                                  bool const want_partial,
516                                                  bool const want_unaligned) const
517 {
518     throw std::logic_error("unimplemented");
519 }
520 
getFragmentBases(uint64_t const Offset,uint64_t const Length) const521 ngs_adapt::StringItf *ReadCollection::Alignment::getFragmentBases(uint64_t const Offset, uint64_t const Length) const
522 {
523     uint64_t const End = Offset + Length;
524     unsigned const seqLen = current->l_seq();
525     unsigned const offset = Offset < seqLen ? Offset : seqLen;
526     unsigned const seqEnd = End < seqLen ? End : seqLen;
527 
528     seqBuffer.resize(0);
529     seqBuffer.reserve(seqLen);
530 
531     for (unsigned i = offset; i < seqEnd; ++i)
532         seqBuffer.append(1, current->seq(i));
533 
534     return new ngs_adapt::StringItf(seqBuffer.data(), seqBuffer.size());
535 }
536 
getFragmentQualities(uint64_t const Offset,uint64_t const Length) const537 ngs_adapt::StringItf *ReadCollection::Alignment::getFragmentQualities(uint64_t const Offset, uint64_t const Length) const
538 {
539     uint64_t const End = Offset + Length;
540     unsigned const seqLen = current->l_seq();
541     unsigned const offset = Offset < seqLen ? Offset : seqLen;
542     unsigned const seqEnd = End < seqLen ? End : seqLen;
543     bool notFF = false;
544     uint8_t const *qual = current->qual();
545 
546     qualBuffer.resize(0);
547     qualBuffer.reserve(seqLen);
548 
549     for (unsigned i = offset; i < seqEnd; ++i) {
550         int const qv = qual[i];
551 
552         notFF |= (qv != 0xFF);
553         qualBuffer.append(1, (char)((qv > 63 ? 63 : qv) + 33));
554     }
555     return new ngs_adapt::StringItf(qualBuffer.data(), notFF ? qualBuffer.size() : 0);
556 }
557 
getReferenceSpec() const558 ngs_adapt::StringItf *ReadCollection::Alignment::getReferenceSpec() const
559 {
560     int const refID = current->refID();
561     HeaderRefInfo const &ri = parent->getRefInfo(refID);
562     std::string const &RNAME = ri.getName();
563     return new ngs_adapt::StringItf(RNAME.data(), RNAME.size());
564 }
565 
getMappingQuality() const566 int32_t ReadCollection::Alignment::getMappingQuality() const
567 {
568     return current->mq();
569 }
570 
getReadGroup() const571 ngs_adapt::StringItf *ReadCollection::Alignment::getReadGroup() const
572 {
573     for (BAMRecord::OptionalField::const_iterator i = current->begin(); i != current->end(); ++i) {
574         char const *tag = i->getTag();
575         if (tag[0] == 'R' && tag[1] == 'G' && i->getValueType() == 'Z') {
576             return new ngs_adapt::StringItf(i->getRawValue(), i->getElementSize());
577         }
578     }
579     return NULL;
580 }
581 
getReadId() const582 ngs_adapt::StringItf *ReadCollection::Alignment::getReadId() const
583 {
584     char const *const QNAME = current->readname();
585     size_t const len = strnlen(QNAME, current->l_read_name());
586     return new ngs_adapt::StringItf(QNAME, len);
587 }
588 
isPrimary() const589 bool ReadCollection::Alignment::isPrimary() const
590 {
591     return (current->flag() & 0x0900) == 0;
592 }
593 
getAlignmentPosition() const594 int64_t ReadCollection::Alignment::getAlignmentPosition() const
595 {
596     return current->pos();
597 }
598 
getAlignmentLength() const599 uint64_t ReadCollection::Alignment::getAlignmentLength() const {
600     return current->refLen();
601 }
602 
getCigar(bool const clipped,char const OPCODE[]) const603 ngs_adapt::StringItf *ReadCollection::Alignment::getCigar(bool const clipped, char const OPCODE[]) const
604 {
605     current->cigarString(cigarBuffer, clipped, OPCODE);
606     return new ngs_adapt::StringItf(cigarBuffer.data(), cigarBuffer.size());
607 }
608 
getIsReversedOrientation() const609 bool ReadCollection::Alignment::getIsReversedOrientation() const
610 {
611     return (current->flag() & 0x0010) != 0;
612 }
613 
614 // TODO: return type should be int64_t
getTemplateLength() const615 uint64_t ReadCollection::Alignment::getTemplateLength() const
616 {
617     return current->tlen();
618 }
619 
hasMate() const620 bool ReadCollection::Alignment::hasMate() const
621 {
622     int const FLAG = current->flag();
623 
624     return (FLAG & 0x0001) != 0 && (FLAG & 0x00C0) != 0 && (FLAG & 0x00C0) != 0x00C0;
625 }
626 
getMateReferenceSpec() const627 ngs_adapt::StringItf *ReadCollection::Alignment::getMateReferenceSpec() const
628 {
629     int const refID = current->next_refID();
630 
631     if (refID < 0)
632         return new ngs_adapt::StringItf("", 0);
633 
634     HeaderRefInfo const &ri = parent->getRefInfo(refID);
635     std::string const &RNEXT = ri.getName();
636     return new ngs_adapt::StringItf(RNEXT.data(), RNEXT.size());
637 }
638 
639 // TODO: rename to isMateReversedOrientation
getMateIsReversedOrientation() const640 bool ReadCollection::Alignment::getMateIsReversedOrientation() const
641 {
642     return (current->flag() & 0x0020) != 0;
643 }
644 
nextAlignment()645 bool ReadCollection::Alignment::nextAlignment()
646 {
647     do {
648         if (current) {
649             delete current;
650             current = 0;
651         }
652         current = parent->ReadBAMRecord();
653         if (!current)
654             return false;
655     } while (shouldSkip());
656     return true;
657 }
658 
openReadCollection(std::string const & path)659 ngs::ReadCollection NGS_BAM::openReadCollection(std::string const &path)
660 {
661     ngs_adapt::ReadCollectionItf *const self = new ReadCollection(path);
662     NGS_ReadCollection_v1 *const c_obj = self->Cast();
663     ngs::ReadCollectionItf *const ngs_itf = ngs::ReadCollectionItf::Cast(c_obj);
664 
665     return ngs::ReadCollection(ngs_itf);
666 }
667