1// Author: Derek Barnett
2
3#include "pbbam/internal/DataSetElement.h"
4
5#include <iostream>
6
7namespace PacBio {
8namespace BAM {
9namespace internal {
10
11// ----------------
12// DataSetElement
13// ----------------
14
15inline DataSetElement::DataSetElement(const std::string& label, const XsdType& xsd)
16    : xsd_(xsd)
17    , label_(label)
18{ }
19
20inline DataSetElement::DataSetElement(const std::string& label,
21                                      const FromInputXml&,
22                                      const XsdType& xsd)
23    : xsd_(xsd)
24    , label_(label, true)
25{ }
26
27inline bool DataSetElement::operator==(const DataSetElement& other) const
28{
29    return xsd_   == other.xsd_   &&
30           label_ == other.label_ &&
31           text_  == other.text_  &&
32           attributes_ == other.attributes_ &&
33           children_   == other.children_;
34}
35
36inline bool DataSetElement::operator!=(const DataSetElement& other) const
37{ return !(*this == other); }
38
39template<typename T>
40const T& DataSetElement::operator[](size_t index) const
41{ return Child<T>(index); }
42
43template<typename T>
44T& DataSetElement::operator[](size_t index)
45{ return Child<T>(index); }
46
47template<typename T>
48const T& DataSetElement::operator[](const std::string& label) const
49{ return Child<T>(label); }
50
51template<typename T>
52T& DataSetElement::operator[](const std::string& label)
53{ return Child<T>(label); }
54
55inline void DataSetElement::AddChild(const DataSetElement& e)
56{ children_.push_back(e); }
57
58inline std::string& DataSetElement::Attribute(const std::string& name)
59{ return attributes_[name]; }
60
61inline const std::string& DataSetElement::Attribute(const std::string& name) const
62{
63    auto iter = attributes_.find(name);
64    if (iter == attributes_.cend())
65        return SharedNullString();
66    return iter->second;
67}
68
69inline void DataSetElement::Attribute(const std::string& name, const std::string& value)
70{ attributes_[name] = value; }
71
72inline const std::map<std::string, std::string>& DataSetElement::Attributes() const
73{ return attributes_; }
74
75inline std::map<std::string, std::string>& DataSetElement::Attributes()
76{ return attributes_; }
77
78template<typename T>
79inline const T& DataSetElement::Child(size_t index) const
80{ return static_cast<const T&>(children_.at(index)); }
81
82template<typename T>
83inline T& DataSetElement::Child(size_t index)
84{ return static_cast<T&>(children_.at(index)); }
85
86template<typename T>
87inline const T& DataSetElement::Child(const std::string& label) const
88{ return Child<T>(IndexOf(label)); }
89
90template<typename T>
91inline T& DataSetElement::Child(const std::string& label)
92{
93    const int i = IndexOf(label);
94    if (i >= 0) {
95        assert(static_cast<size_t>(i) < NumChildren());
96        return Child<T>(i);
97    } else {
98        AddChild(DataSetElement(label));
99        return Child<T>(NumChildren()-1);
100    }
101}
102
103inline const std::vector<DataSetElement>& DataSetElement::Children() const
104{ return children_; }
105
106inline std::vector<DataSetElement>& DataSetElement::Children()
107{ return children_; }
108
109inline const std::string& DataSetElement::ChildText(const std::string& label) const
110{
111    if (!HasChild(label))
112        return SharedNullString();
113    return Child<DataSetElement>(label).Text();
114}
115
116inline std::string& DataSetElement::ChildText(const std::string& label)
117{
118    if (!HasChild(label))
119        AddChild(DataSetElement(label));
120    return Child<DataSetElement>(label).Text();
121}
122
123inline bool DataSetElement::HasAttribute(const std::string& name) const
124{ return attributes_.find(name) != attributes_.cend(); }
125
126inline bool DataSetElement::HasChild(const std::string& label) const
127{ return IndexOf(label) != -1; }
128
129inline int DataSetElement::IndexOf(const std::string& label) const
130{
131    const size_t count = NumChildren();
132    for (size_t i = 0; i < count; ++i) {
133        const DataSetElement& child = children_.at(i);
134        if (child.LocalNameLabel() == label || child.label_ == label)
135            return i;
136    }
137    return -1;
138}
139
140inline const boost::string_ref DataSetElement::LocalNameLabel() const
141{ return label_.LocalName(); }
142
143inline const boost::string_ref DataSetElement::PrefixLabel() const
144{ return label_.Prefix(); }
145
146inline const std::string& DataSetElement::QualifiedNameLabel() const
147{ return label_.QualifiedName(); }
148
149//inline std::string& DataSetElement::Label()
150//{ return label_.QualifiedName(); }
151
152inline void DataSetElement::Label(const std::string& label)
153{ label_ = XmlName(label, true); }
154
155inline size_t DataSetElement::NumAttributes() const
156{ return attributes_.size(); }
157
158inline size_t DataSetElement::NumChildren() const
159{ return children_.size(); }
160
161inline void DataSetElement::RemoveChild(const DataSetElement& e)
162{
163    children_.erase(
164        std::remove(children_.begin(),
165                    children_.end(),
166                    e),
167        children_.end()
168    );
169}
170
171inline void DataSetElement::ChildText(const std::string& label,
172                                         const std::string& text)
173{
174    if (!HasChild(label)) {
175        DataSetElement e(label);
176        e.Text(text);
177        AddChild(e);
178    } else {
179        Child<DataSetElement>(label).Text(text);
180    }
181}
182
183inline bool DataSetElement::IsVerbatimLabel() const
184{ return label_.Verbatim(); }
185
186inline const std::string& DataSetElement::Text() const
187{ return text_; }
188
189inline std::string& DataSetElement::Text()
190{ return text_; }
191
192inline void DataSetElement::Text(const std::string& text)
193{ text_ = text; }
194
195inline const XsdType& DataSetElement::Xsd() const
196{ return xsd_; }
197
198// ----------------
199// XmlName
200// ----------------
201
202inline XmlName::XmlName(std::string fullName, bool verbatim)
203    : qualifiedName_(std::move(fullName))
204    , prefixSize_(0)
205    , localNameOffset_(0)
206    , localNameSize_(0)
207    , verbatim_(verbatim)
208{
209    const size_t colonFound = qualifiedName_.find(':');
210    if (colonFound == std::string::npos || colonFound == 0)
211        localNameSize_ = qualifiedName_.size();
212    else {
213        prefixSize_ = colonFound;
214        localNameSize_ = (qualifiedName_.size() - colonFound) - 1;
215    }
216
217    // adjust for colon if prefix present
218    localNameOffset_ = prefixSize_;
219    if (prefixSize_ != 0)
220        ++localNameOffset_;
221}
222
223inline XmlName::XmlName(const std::string& localName,
224                        const std::string& prefix)
225    : prefixSize_(prefix.size())
226    , localNameOffset_(prefixSize_)
227    , localNameSize_(localName.size())
228    , verbatim_(true)
229{
230    qualifiedName_.clear();
231    qualifiedName_.reserve(localNameSize_+ prefixSize_ + 1);
232    qualifiedName_.append(prefix);
233    if (!qualifiedName_.empty())
234        qualifiedName_.append(1, ':');
235    qualifiedName_.append(localName);
236
237    // adjust for colon if prefix present
238    if (prefixSize_ != 0)
239        ++localNameOffset_;
240}
241
242inline bool XmlName::operator==(const XmlName& other) const
243{ return qualifiedName_ == other.qualifiedName_; }
244
245inline bool XmlName::operator!=(const XmlName& other) const
246{ return !(*this == other); }
247
248inline const boost::string_ref XmlName::LocalName() const
249{ return boost::string_ref(qualifiedName_.data() + localNameOffset_, localNameSize_); }
250
251inline const boost::string_ref XmlName::Prefix() const
252{ return boost::string_ref(qualifiedName_.data(), prefixSize_); }
253
254inline const std::string& XmlName::QualifiedName() const
255{ return qualifiedName_; }
256
257inline bool XmlName::Verbatim() const
258{ return verbatim_; }
259
260} // namespace internal
261} // namespace BAM
262} // namespace PacBio
263