1use crate::error::{Result, SzConfigError};
8use crate::helpers;
9use serde_json::{Value, json};
10
11#[derive(Debug, Clone)]
17pub struct AddBehaviorOverrideParams<'a> {
18 pub feature_code: &'a str,
19 pub usage_type: &'a str,
20 pub behavior: &'a str,
21}
22
23impl<'a> AddBehaviorOverrideParams<'a> {
24 pub fn new(feature_code: &'a str, usage_type: &'a str, behavior: &'a str) -> Self {
25 Self {
26 feature_code,
27 usage_type,
28 behavior,
29 }
30 }
31}
32
33pub fn add_behavior_override(
58 config_json: &str,
59 params: AddBehaviorOverrideParams,
60) -> Result<String> {
61 let config: Value =
62 serde_json::from_str(config_json).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
63
64 let ftype_id = helpers::lookup_feature_id(config_json, params.feature_code)?;
66
67 let (frequency, exclusivity, stability) = parse_behavior_code(params.behavior)?;
69
70 let utype_upper = params.usage_type.to_uppercase();
71
72 let fbovr_array = config
74 .get("G2_CONFIG")
75 .and_then(|g| g.get("CFG_FBOVR"))
76 .and_then(|v| v.as_array())
77 .ok_or_else(|| SzConfigError::MissingSection("CFG_FBOVR".to_string()))?;
78
79 if fbovr_array.iter().any(|item| {
80 item["FTYPE_ID"].as_i64() == Some(ftype_id)
81 && item["UTYPE_CODE"].as_str() == Some(&utype_upper)
82 }) {
83 return Err(SzConfigError::AlreadyExists(format!(
84 "Behavior override already exists for feature {} with usage type {}",
85 params.feature_code, utype_upper
86 )));
87 }
88
89 let override_record = json!({
91 "FTYPE_ID": ftype_id,
92 "UTYPE_CODE": utype_upper,
93 "FTYPE_FREQ": frequency,
94 "FTYPE_EXCL": exclusivity,
95 "FTYPE_STAB": stability
96 });
97
98 helpers::add_to_config_array(config_json, "CFG_FBOVR", override_record)
100}
101
102pub fn delete_behavior_override(
115 config_json: &str,
116 feature_code: &str,
117 usage_type: &str,
118) -> Result<String> {
119 let mut config: Value =
120 serde_json::from_str(config_json).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
121
122 let ftype_id = helpers::lookup_feature_id(config_json, feature_code)?;
124 let utype_upper = usage_type.to_uppercase();
125
126 let fbovr_array = config
127 .get_mut("G2_CONFIG")
128 .and_then(|g| g.get_mut("CFG_FBOVR"))
129 .and_then(|v| v.as_array_mut())
130 .ok_or_else(|| SzConfigError::MissingSection("CFG_FBOVR".to_string()))?;
131
132 let original_len = fbovr_array.len();
133 fbovr_array.retain(|item| {
134 !(item["FTYPE_ID"].as_i64() == Some(ftype_id)
135 && item["UTYPE_CODE"].as_str() == Some(&utype_upper))
136 });
137
138 if fbovr_array.len() == original_len {
139 return Err(SzConfigError::NotFound(format!(
140 "Behavior override not found for feature {feature_code} with usage type {utype_upper}"
141 )));
142 }
143
144 serde_json::to_string(&config).map_err(|e| SzConfigError::JsonParse(e.to_string()))
145}
146
147pub fn get_behavior_override(
157 config_json: &str,
158 feature_code: &str,
159 usage_type: &str,
160) -> Result<Value> {
161 let config: Value =
162 serde_json::from_str(config_json).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
163
164 let ftype_id = helpers::lookup_feature_id(config_json, feature_code)?;
165 let utype_upper = usage_type.to_uppercase();
166
167 config
168 .get("G2_CONFIG")
169 .and_then(|g| g.get("CFG_FBOVR"))
170 .and_then(|v| v.as_array())
171 .ok_or_else(|| SzConfigError::MissingSection("CFG_FBOVR".to_string()))?
172 .iter()
173 .find(|item| {
174 item["FTYPE_ID"].as_i64() == Some(ftype_id)
175 && item["UTYPE_CODE"].as_str() == Some(&utype_upper)
176 })
177 .cloned()
178 .ok_or_else(|| {
179 SzConfigError::NotFound(format!(
180 "Behavior override not found for feature {feature_code} with usage type {utype_upper}"
181 ))
182 })
183}
184
185pub fn list_behavior_overrides(config_json: &str) -> Result<Vec<Value>> {
193 let config: Value =
194 serde_json::from_str(config_json).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
195
196 let fbovr_array = config
197 .get("G2_CONFIG")
198 .and_then(|g| g.get("CFG_FBOVR"))
199 .and_then(|v| v.as_array())
200 .ok_or_else(|| SzConfigError::MissingSection("CFG_FBOVR".to_string()))?;
201
202 let mut result: Vec<Value> = fbovr_array.to_vec();
203
204 result.sort_by_key(|item| item["FTYPE_ID"].as_i64().unwrap_or(0));
206
207 Ok(result)
208}
209
210fn parse_behavior_code(behavior: &str) -> Result<(&'static str, &'static str, &'static str)> {
225 let mut code = behavior.to_uppercase();
226 let mut exclusivity = "No";
227 let mut stability = "No";
228
229 if code != "NAME" && code != "NONE" {
231 if code.contains('E') {
232 exclusivity = "Yes";
233 code = code.replace('E', "");
234 }
235 if code.contains('S') {
236 stability = "Yes";
237 code = code.replace('S', "");
238 }
239 }
240
241 let frequency: &'static str = match code.as_str() {
243 "A1" => "A1",
244 "F1" => "F1",
245 "FF" => "FF",
246 "FM" => "FM",
247 "FVM" => "FVM",
248 "NONE" => "NONE",
249 "NAME" => "NAME",
250 _ => {
251 return Err(SzConfigError::InvalidInput(format!(
252 "Invalid behavior code '{behavior}'. Valid codes: A1, F1, FF, FM, FVM, NONE, NAME (with optional E/S suffixes)"
253 )));
254 }
255 };
256
257 Ok((frequency, exclusivity, stability))
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 const TEST_CONFIG: &str = r#"{
265 "G2_CONFIG": {
266 "CFG_FTYPE": [
267 {
268 "FTYPE_ID": 1,
269 "FTYPE_CODE": "TEST_FEATURE",
270 "FTYPE_DESC": "Test Feature"
271 }
272 ],
273 "CFG_FBOVR": []
274 }
275}"#;
276
277 #[test]
278 fn test_add_behavior_override() {
279 let config = add_behavior_override(
280 TEST_CONFIG,
281 AddBehaviorOverrideParams::new("TEST_FEATURE", "BUSINESS", "F1E"),
282 )
283 .expect("Failed to add behavior override");
284
285 let config_val: Value = serde_json::from_str(&config).unwrap();
286 let overrides = &config_val["G2_CONFIG"]["CFG_FBOVR"];
287
288 assert_eq!(overrides.as_array().unwrap().len(), 1);
289
290 let override_rec = &overrides[0];
291 assert_eq!(override_rec["FTYPE_ID"], 1);
292 assert_eq!(override_rec["UTYPE_CODE"], "BUSINESS");
293 assert_eq!(override_rec["FTYPE_FREQ"], "F1");
294 assert_eq!(override_rec["FTYPE_EXCL"], "Yes");
295 assert_eq!(override_rec["FTYPE_STAB"], "No");
296 }
297
298 #[test]
299 fn test_delete_behavior_override() {
300 let config = add_behavior_override(
301 TEST_CONFIG,
302 AddBehaviorOverrideParams::new("TEST_FEATURE", "BUSINESS", "F1E"),
303 )
304 .expect("Failed to add");
305
306 let config = delete_behavior_override(&config, "TEST_FEATURE", "BUSINESS")
307 .expect("Failed to delete");
308
309 let config_val: Value = serde_json::from_str(&config).unwrap();
310 let overrides = &config_val["G2_CONFIG"]["CFG_FBOVR"];
311 assert_eq!(overrides.as_array().unwrap().len(), 0);
312 }
313
314 #[test]
315 fn test_list_behavior_overrides() {
316 let config = add_behavior_override(
317 TEST_CONFIG,
318 AddBehaviorOverrideParams::new("TEST_FEATURE", "BUSINESS", "F1E"),
319 )
320 .expect("Failed to add first");
321 let config = add_behavior_override(
322 &config,
323 AddBehaviorOverrideParams::new("TEST_FEATURE", "MOBILE", "FM"),
324 )
325 .expect("Failed to add second");
326
327 let overrides = list_behavior_overrides(&config).expect("Failed to list");
328 assert_eq!(overrides.len(), 2);
329 assert_eq!(overrides[0]["UTYPE_CODE"], "BUSINESS");
330 assert_eq!(overrides[1]["UTYPE_CODE"], "MOBILE");
331 }
332
333 #[test]
334 fn test_parse_behavior_code_simple() {
335 let (freq, excl, stab) = parse_behavior_code("FM").unwrap();
336 assert_eq!(freq, "FM");
337 assert_eq!(excl, "No");
338 assert_eq!(stab, "No");
339 }
340
341 #[test]
342 fn test_parse_behavior_code_with_modifiers() {
343 let (freq, excl, stab) = parse_behavior_code("F1ES").unwrap();
344 assert_eq!(freq, "F1");
345 assert_eq!(excl, "Yes");
346 assert_eq!(stab, "Yes");
347 }
348
349 #[test]
350 fn test_parse_behavior_code_name() {
351 let (freq, excl, stab) = parse_behavior_code("NAME").unwrap();
352 assert_eq!(freq, "NAME");
353 assert_eq!(excl, "No");
354 assert_eq!(stab, "No");
355 }
356
357 #[test]
358 fn test_behavior_override_duplicate() {
359 let config = add_behavior_override(
360 TEST_CONFIG,
361 AddBehaviorOverrideParams::new("TEST_FEATURE", "BUSINESS", "F1E"),
362 )
363 .expect("Failed to add first");
364
365 let result = add_behavior_override(
366 &config,
367 AddBehaviorOverrideParams::new("TEST_FEATURE", "BUSINESS", "FM"),
368 );
369 assert!(result.is_err());
370 assert!(result.unwrap_err().to_string().contains("already exists"));
371 }
372}