1use serde::Serialize;
2
3pub(crate) static DEFAULT_CSS_SELECTOR: &str = "main";
4
5#[derive(Debug, Clone, Serialize)]
6#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
7pub struct Links {
8 fee_info: Link,
10 feed_in_revenue_info: Option<Link>,
12 eltariff_api: Option<&'static str>,
14}
15
16impl Links {
17 pub const fn fee_info(&self) -> &Link {
18 &self.fee_info
19 }
20
21 pub(crate) const fn builder() -> LinksBuilder {
22 LinksBuilder::new()
23 }
24}
25
26pub(crate) struct LinksBuilder {
27 fee_info: Option<Link>,
28 feed_in_revenue_info: Option<Link>,
29 eltariff_api: Option<&'static str>,
30}
31
32impl LinksBuilder {
33 pub(crate) const fn new() -> Self {
34 Self {
35 fee_info: None,
36 feed_in_revenue_info: None,
37 eltariff_api: None,
38 }
39 }
40
41 pub(crate) const fn fee_info(mut self, link: &'static str, css_selector: &'static str) -> Self {
42 self.fee_info = Some(
43 Link::builder(link)
44 .plain_content_locator(css_selector)
45 .build(),
46 );
47 self
48 }
49
50 pub(crate) const fn fee_info_default(mut self, link: &'static str) -> Self {
52 self.fee_info = Some(Link::builder(link).content_locator_default().build());
53 self
54 }
55
56 pub(crate) const fn fee_info_complex(
57 mut self,
58 link: &'static str,
59 content_locator: ContentLocator,
60 ) -> Self {
61 self.fee_info = Some(Link::builder(link).content_locator(content_locator).build());
62 self
63 }
64
65 pub(crate) const fn feed_in_revenue_info(
66 mut self,
67 link: &'static str,
68 css_selector: &'static str,
69 ) -> Self {
70 self.feed_in_revenue_info = Some(
71 Link::builder(link)
72 .plain_content_locator(css_selector)
73 .build(),
74 );
75 self
76 }
77
78 pub(crate) const fn eltariff_api(mut self, link: &'static str) -> Self {
79 self.eltariff_api = Some(link);
80 self
81 }
82
83 pub(crate) const fn build(self) -> Links {
84 Links {
85 fee_info: self.fee_info.expect("`fee_info` not specified"),
86 feed_in_revenue_info: self.feed_in_revenue_info,
87 eltariff_api: self.eltariff_api,
88 }
89 }
90}
91
92#[derive(Debug, Clone, Copy, Serialize)]
93#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
94pub enum TargetContainer {
95 Current,
96 Parent,
97 Ancestor(usize),
98}
99
100#[derive(Debug, Clone, Serialize)]
102#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
103pub enum ContentTarget {
104 TextWithLinks,
105 Attribute(&'static str),
107}
108
109#[derive(Debug, Clone, Serialize)]
110#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
111pub struct ContentLocator {
112 method: LocatorMethod,
113 content: ContentTarget,
114 uses_default_locator: bool,
115}
116
117impl ContentLocator {
118 pub(crate) const fn new(method: LocatorMethod, content: ContentTarget) -> Self {
119 Self {
120 method,
121 content,
122 uses_default_locator: false,
123 }
124 }
125
126 pub const fn method(&self) -> &LocatorMethod {
127 &self.method
128 }
129
130 pub const fn uses_default_locator(&self) -> bool {
131 self.uses_default_locator
132 }
133
134 pub const fn content_target(&self) -> &ContentTarget {
135 &self.content
136 }
137
138 pub(crate) const fn new_starts_with(
139 needle: &'static str,
140 target_container: TargetContainer,
141 content: ContentTarget,
142 ) -> ContentLocator {
143 Self::new(
144 LocatorMethod::TextStartsWith {
145 needle,
146 target_container,
147 },
148 content,
149 )
150 }
151}
152
153#[derive(Debug, Clone, Serialize)]
154#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
155pub enum LocatorMethod {
156 CssSelector(&'static str),
157 TextStartsWith {
158 needle: &'static str,
159 target_container: TargetContainer,
160 },
161}
162
163impl LocatorMethod {
164 pub fn target_container(&self) -> TargetContainer {
165 match self {
166 Self::CssSelector(_) => TargetContainer::Current,
167 Self::TextStartsWith {
168 target_container, ..
169 } => *target_container,
170 }
171 }
172}
173
174#[derive(Debug, Clone, Serialize)]
175#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
176pub struct Link {
177 link: &'static str,
178 content_locator: ContentLocator,
179}
180
181impl Link {
182 pub const fn link(&self) -> &str {
183 self.link
184 }
185
186 pub const fn content_locator(&self) -> &ContentLocator {
187 &self.content_locator
188 }
189
190 pub(crate) const fn builder(link: &'static str) -> LinkBuilder {
191 LinkBuilder::new(link)
192 }
193}
194
195pub struct LinkBuilder {
196 link: &'static str,
197 content_locator: Option<ContentLocator>,
198}
199
200impl LinkBuilder {
201 pub(crate) const fn new(link: &'static str) -> Self {
202 Self {
203 link,
204 content_locator: None,
205 }
206 }
207
208 pub(crate) const fn content_locator(mut self, locator: ContentLocator) -> Self {
209 self.content_locator = Some(locator);
210 self
211 }
212
213 pub(crate) const fn plain_content_locator(mut self, css_selector: &'static str) -> Self {
214 self.content_locator = Some(ContentLocator::new(
215 LocatorMethod::CssSelector(css_selector),
216 ContentTarget::TextWithLinks,
217 ));
218 self
219 }
220
221 pub(crate) const fn content_locator_default(mut self) -> Self {
222 self.content_locator = Some(ContentLocator {
223 method: LocatorMethod::CssSelector(DEFAULT_CSS_SELECTOR),
224 content: ContentTarget::TextWithLinks,
225 uses_default_locator: true,
226 });
227 self
228 }
229
230 pub(crate) const fn build(self) -> Link {
231 Link {
232 link: self.link,
233 content_locator: self.content_locator.expect("`locator` missing"),
234 }
235 }
236}