BadScript 2
Loading...
Searching...
No Matches
BadSettings.cs
Go to the documentation of this file.
1using System.Collections.Concurrent;
2using System.Text;
3
4using Newtonsoft.Json.Linq;
5
6namespace BadScript2.Settings;
7
11public class BadSettings
12{
16 private readonly ConcurrentDictionary<string, BadSettings> m_Properties;
17
21 private object? m_Cache;
22
26 private bool m_IsDirty;
27
31 private JToken? m_Value;
32
37 public BadSettings(string sourcePath)
38 {
39 SourcePath = sourcePath;
40 m_Value = null;
41 m_IsDirty = true;
42 m_Properties = new ConcurrentDictionary<string, BadSettings>();
43 }
44
50 public BadSettings(JToken? value, string sourcePath)
51 {
52 m_Value = value;
53 SourcePath = sourcePath;
54 m_IsDirty = true;
55 m_Properties = new ConcurrentDictionary<string, BadSettings>();
56 }
57
63 public BadSettings(Dictionary<string, BadSettings> properties, string sourcePath)
64 {
65 m_Value = null;
66 m_IsDirty = true;
67 m_Properties = new ConcurrentDictionary<string, BadSettings>(properties);
68 SourcePath = sourcePath;
69
70 foreach (KeyValuePair<string, BadSettings> kvp in m_Properties)
71 {
72 kvp.Value.OnValueChanged += PropertyValueChanged;
73 }
74 }
75
76 public bool HasSourcePath => !string.IsNullOrEmpty(SourcePath);
77
81 public string SourcePath { get; }
82
86 public IEnumerable<string> PropertyNames => m_Properties.Keys;
87
88 public event Action OnValueChanged = delegate { };
89
90 private void PropertyValueChanged()
91 {
92 m_IsDirty = true;
94 }
95
96 private void InvokeValueChanged()
97 {
99 }
100
105 public JToken? GetValue()
106 {
107 return m_Value;
108 }
109
115 public T? GetValue<T>()
116 {
117 if (!m_IsDirty)
118 {
119 return (T?)m_Cache;
120 }
121
122 if (m_Value == null)
123 {
124 return default;
125 }
126
127 T? v = m_Value.ToObject<T>();
128
129 m_Cache = v;
130 m_IsDirty = false;
131
132 return v;
133 }
134
139 public bool HasValue()
140 {
141 return m_Value != null;
142 }
143
149 private bool HasValue<T>()
150 {
151 if (m_Value?.Type == JTokenType.Array && !typeof(T).IsArray)
152 {
153 return false;
154 }
155
156 return m_Value != null && m_Value.ToObject<T>() != null;
157 }
158
164 public void SetValue(JToken? value, bool invokeOnChange = true)
165 {
166 m_Value = value;
167
168 if (invokeOnChange)
169 {
171 }
172 else
173 {
174 m_IsDirty = true;
175 }
176 }
177
182 private void SetValue(object? value)
183 {
184 SetValue(value == null ? JValue.CreateNull() : JToken.FromObject(value));
185 }
186
192 public bool HasProperty(string propertyName)
193 {
194 return m_Properties.ContainsKey(propertyName);
195 }
196
202 public BadSettings GetProperty(string propertyName)
203 {
204 return m_Properties[propertyName];
205 }
206
213 public void SetProperty(string propertyName, BadSettings value, bool invokeOnChange = true)
214 {
215 if (m_Properties.TryGetValue(propertyName, out BadSettings? old))
216 {
217 old.OnValueChanged -= PropertyValueChanged;
218 }
219
220 m_Properties[propertyName] = value;
221
222 if (invokeOnChange)
223 {
225 }
226 else
227 {
228 m_IsDirty = true;
229 }
230 }
231
237 public bool RemoveProperty(string propertyName, bool invokeOnChange = true)
238 {
239 if (m_Properties.TryGetValue(propertyName, out BadSettings? old))
240 {
241 old.OnValueChanged -= PropertyValueChanged;
242 }
243
244 bool r = m_Properties.TryRemove(propertyName, out _);
245
246 if (invokeOnChange)
247 {
249 }
250 else
251 {
252 m_IsDirty = true;
253 }
254
255 return r;
256 }
257
258
264 public void Populate(bool invokeOnChanged, params BadSettings[] settings)
265 {
266 if (m_Value is JArray arr)
267 {
268 foreach (BadSettings setting in settings)
269 {
270 if (!setting.HasValue())
271 {
272 continue;
273 }
274
275 if (setting.GetValue() is JArray arr2)
276 {
277 foreach (JToken jToken in arr2)
278 {
279 arr.Add(jToken);
280 }
281 }
282 else
283 {
284 arr.Add(setting.GetValue() ?? JValue.CreateNull());
285 }
286 }
287 }
288
289 foreach (BadSettings setting in settings)
290 {
291 foreach (string propertyName in setting.PropertyNames)
292 {
293 if (HasProperty(propertyName))
294 {
295 GetProperty(propertyName)
296 .Populate(false, setting.GetProperty(propertyName));
297 }
298 else
299 {
300 SetProperty(propertyName, setting.GetProperty(propertyName), false);
301 }
302 }
303 }
304
305 if (invokeOnChanged)
306 {
308 }
309 else
310 {
311 m_IsDirty = true;
312 }
313 }
314
321 public T? FindProperty<T>(string propertyName) where T : class
322 {
323 BadSettings? settings = FindProperty(propertyName);
324
325 return settings?.GetValue<T>();
326 }
327
333 public BadSettings FindOrCreateProperty(string propertyPath)
334 {
335 string[] path = propertyPath.Split('.');
336 BadSettings current = this;
337
338 foreach (string s in path)
339 {
340 if (!current.HasProperty(s))
341 {
342 BadSettings se = new BadSettings(string.Empty);
343 current.SetProperty(s, se);
344 current = se;
345 }
346 else
347 {
348 current = current.GetProperty(s);
349 }
350 }
351
352 return current;
353 }
354
360 public BadSettings? FindProperty(string propertyPath)
361 {
362 string[] path = propertyPath.Split('.');
363 BadSettings current = this;
364
365 foreach (string s in path)
366 {
367 if (!current.HasProperty(s))
368 {
369 return null;
370 }
371
372 current = current.GetProperty(s);
373 }
374
375 return current;
376 }
377
382 public override string ToString()
383 {
384 if (HasValue())
385 {
386 return GetValue()
387 ?.ToString() ??
388 "NULL";
389 }
390
391 StringBuilder sb = new StringBuilder();
392
393 sb.AppendLine("{");
394
395 foreach (string propertyName in PropertyNames)
396 {
397 BadSettings s = GetProperty(propertyName);
398
399 string str = s.ToString()
400 .Replace("\n", "\n\t");
401 sb.AppendLine($" {propertyName}: {str}");
402 }
403
404 sb.AppendLine("}");
405
406 return sb.ToString();
407 }
408
420 private static string ResolveEnvironmentVariables(BadSettings root, BadSettings parent, string str)
421 {
422 for (int i = 0; i < str.Length; i++)
423 {
424 if (str[i] != '$' || i + 1 >= str.Length || str[i + 1] != '(')
425 {
426 continue;
427 }
428
429 int end = str.IndexOf(')', i + 2);
430
431 if (end == -1)
432 {
433 throw new Exception("Unclosed environment variable");
434 }
435
436 string envVar = str.Substring(i + 2, end - i - 2);
437
438 string? env = root.FindProperty<string>(envVar);
439
440 if (env == null)
441 {
442 env = parent.FindProperty<string>(envVar);
443
444 if (env == null)
445 {
446 throw new Exception($"Environment variable '{envVar}' not found");
447 }
448 }
449
450 str = str.Replace(str.Substring(i, end - i + 1), env);
451 i--;
452 }
453
454 return str;
455 }
456
462 {
463 ResolveEnvironmentVariables(root, root, root);
464 }
465
472 public static void ResolveEnvironmentVariables(BadSettings root, BadSettings settings, BadSettings parent)
473 {
474 if (settings.HasValue<string>())
475 {
476 string value = settings.GetValue<string>()!;
477
478 settings.SetValue(ResolveEnvironmentVariables(root, parent, value));
479 }
480 else if (settings.HasValue<string[]>())
481 {
482 string[] value = settings.GetValue<string[]>()!;
483
484 for (int i = 0; i < value.Length; i++)
485 {
486 value[i] = ResolveEnvironmentVariables(root, parent, value[i]);
487 }
488
489 settings.SetValue(value);
490 }
491
492 foreach (string propertyName in settings.PropertyNames)
493 {
494 ResolveEnvironmentVariables(root, settings.GetProperty(propertyName), settings);
495 }
496 }
497}
Public Api for the Settings System.
void Populate(bool invokeOnChanged, params BadSettings[] settings)
Populates the current object with the settings provided.
BadSettings? FindProperty(string propertyPath)
Finds a property based on the property path relative to this object.
JToken? m_Value
The Json Token of the Settings Object.
IEnumerable< string > PropertyNames
The Property Names of the Settings Object.
BadSettings(JToken? value, string sourcePath)
Creates a new Settings Object from a Json Token.
object? m_Cache
Cache for the Serialized Value of the Settings.
bool m_IsDirty
Indicates if the current object is dirty and needs to be re-serialized.
override string ToString()
Returns a string representation of the current object.
string SourcePath
The Source Path of the Settings Object.
void SetProperty(string propertyName, BadSettings value, bool invokeOnChange=true)
Sets the Property with the given Name.
void SetValue(JToken? value, bool invokeOnChange=true)
Sets the Json Token of the Current Settings Object.
bool HasValue()
Returns true if the Settings Object has a JToken Value.
static void ResolveEnvironmentVariables(BadSettings root)
Resolves Environment Variables in the current object.
T? GetValue< T >()
Returns a Deserialized Value of the Settings Object.
static string ResolveEnvironmentVariables(BadSettings root, BadSettings parent, string str)
Resolves Environment Variables in the current object.
BadSettings(Dictionary< string, BadSettings > properties, string sourcePath)
Creates a new Settings Object from a Dictionary of Properties.
readonly ConcurrentDictionary< string, BadSettings > m_Properties
The properties of the Current Settings Object.
bool HasValue< T >()
Returns true if the Settings Object can be Deserialized into the given Type.
BadSettings GetProperty(string propertyName)
Returns the Property with the given Name.
void SetValue(object? value)
Sets the Json Token of the Current Settings Object.
JToken? GetValue()
Returns the Json Token of the Settings Object.
BadSettings FindOrCreateProperty(string propertyPath)
Finds a property based on the property path relative to this object.
BadSettings(string sourcePath)
Creates a new empty Settings Object.
bool HasProperty(string propertyName)
Returns true if the Settings Object has the given Property.
bool RemoveProperty(string propertyName, bool invokeOnChange=true)
Removes the Property with the given Name.
T? FindProperty< T >(string propertyName)
Finds a property based on the property path relative to this object.
static void ResolveEnvironmentVariables(BadSettings root, BadSettings settings, BadSettings parent)
Resolves Environment Variables in the current object.
Contains the Settings Implementation.