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
27from ctypes import byref, c_char, c_int, c_int32, c_uint32, c_int64, c_uint64, c_void_p
28from . import NGS
29
30from .String import NGS_String, NGS_RawString, getNGSString, getNGSValue
31
32from .Fragment import Fragment
33
34# Represents an alignment between a Fragment and Reference sub-sequence
35# provides a path to Read and mate Alignment
36
37class Alignment(Fragment):
38
39    # AlignmentFilter constants
40    passFailed          = 1
41    passDuplicates      = 2
42    minMapQuality       = 4
43    maxMapQuality       = 8
44    noWraparound        = 16
45    startWithinSlice    = 32
46
47    # AlignmentCategory constants
48    primaryAlignment    = 1
49    secondaryAlignment  = 2
50    all                 = primaryAlignment | secondaryAlignment
51
52    # ClipEdge constants
53    clipLeft            = 0
54    clipRight           = 1
55
56
57    def getAlignmentId(self):
58        """Retrieve an identifying String that can be used for later access.
59        The id will be unique within ReadCollection.
60        :returns: alignment id string
61        :throws: ErrorMsg if the property cannot be retrieved
62        """
63        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetAlignmentId)
64
65    # ------------------------------------------------------------------
66    # Reference
67
68    def getReferenceSpec(self):
69        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetReferenceSpec)
70
71    def getMappingQuality(self):
72        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetMappingQuality, c_int32)
73
74    def getReferenceBases(self):
75        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetReferenceBases)
76
77    # ------------------------------------------------------------------
78    # Fragment
79
80    def getReadGroup(self):
81        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetReadGroup)
82
83    def getReadId(self):
84        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetReadId)
85
86    def getClippedFragmentBases(self):
87        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetClippedFragmentBases)
88
89    def getClippedFragmentQualities(self):
90        """
91        :returns: clipped fragment phred quality values using ASCII offset of 33
92        """
93        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetClippedFragmentQualities)
94
95    def getAlignedFragmentBases(self):
96        """
97        :returns: fragment bases in their aligned orientation
98        """
99        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetAlignedFragmentBases)
100
101    # ------------------------------------------------------------------
102    # details of this alignment
103
104    def getAlignmentCategory(self):
105        """Alignments are categorized as primary or secondary (alternate).
106        :returns: either Alignment.primaryAlignment or Alignment.secondaryAlignment
107        :throws: ErrorMsg if the property cannot be retrieved
108        """
109        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetAlignmentCategory, c_uint32)
110
111    def getAlignmentPosition(self):
112        """Retrieve the Alignment's starting position on the Reference
113        :returns: unsigned 0-based offset from start of Reference
114        :throws: ErrorMsg if the property cannot be retrieved
115        """
116        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetAlignmentPosition, c_int64)
117
118    def getAlignmentLength(self):
119        """Retrieve the projected length of an Alignment projected upon Reference.
120        :returns: unsigned length of projection
121        :throws: ErrorMsg if the property cannot be retrieved
122        """
123        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetAlignmentLength, c_uint64)
124
125    def getIsReversedOrientation(self):
126        """Test if orientation is reversed with respect to the Reference sequence.
127        :returns: true if reversed
128        :throws: ErrorMsg if the property cannot be retrieved
129        """
130        return bool(getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetIsReversedOrientation, c_int))
131
132    def getSoftClip(self, edge):
133        ret = c_int32()
134        ngs_str_err = NGS_RawString()
135        try:
136            res = NGS.lib_manager.PY_NGS_AlignmentGetSoftClip(self.ref, edge, byref(ret), byref(ngs_str_err.ref))
137        finally:
138            ngs_str_err.close()
139
140        return ret.value
141
142    def getTemplateLength(self):
143        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetTemplateLength, c_uint64)
144
145    def getShortCigar(self, clipped):
146        """
147        :returns: a text string describing alignment details
148        """
149        ngs_str_err = NGS_RawString()
150        try:
151            ngs_str_ret = NGS_String()
152            try:
153                res = NGS.lib_manager.PY_NGS_AlignmentGetShortCigar(self.ref, clipped, byref(ngs_str_ret.ref), byref(ngs_str_err.ref))
154                return ngs_str_ret.getPyString()
155            finally:
156                ngs_str_ret.close()
157        finally:
158            ngs_str_err.close()
159
160    def getLongCigar(self, clipped):
161        """
162        :returns: a text string describing alignment details
163        """
164        ngs_str_err = NGS_RawString()
165        try:
166            ngs_str_ret = NGS_String()
167            try:
168                res = NGS.lib_manager.PY_NGS_AlignmentGetLongCigar(self.ref, clipped, byref(ngs_str_ret.ref), byref(ngs_str_err.ref))
169                return ngs_str_ret.getPyString()
170            finally:
171                ngs_str_ret.close()
172        finally:
173            ngs_str_err.close()
174
175    def getRNAOrientation(self):
176        """
177        :returns: '+' if positive strand is transcribed
178        :returns: '-' if negative strand is transcribed
179        :returns: '?' if unknown
180        """
181        return getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetRNAOrientation, c_char).decode("utf-8")
182
183    # ------------------------------------------------------------------
184    # details of mate alignment
185
186    def hasMate(self):
187        return bool(getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentHasMate, c_int))
188
189    def getMateAlignmentId(self):
190        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetMateAlignmentId)
191
192    def getMateAlignment(self):
193        ret = Alignment()
194        ret.ref = getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetMateAlignment, c_void_p) # TODO: check if it works
195        return ret
196
197    def getMateReferenceSpec(self):
198        return getNGSString(self, NGS.lib_manager.PY_NGS_AlignmentGetMateReferenceSpec)
199
200    def getMateIsReversedOrientation(self):
201        return bool(getNGSValue(self, NGS.lib_manager.PY_NGS_AlignmentGetMateIsReversedOrientation, c_int))
202