blob: 2429e24066f0dc7e010242906282ff57e3239aef [file] [log] [blame]
Constantin Ziesche857c7ab2020-02-25 11:24:51 +01001/*******************************************************************************
2* Copyright (c) 2020 Robert Bosch GmbH
3* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
4*
5* This program and the accompanying materials are made available under the
6* terms of the Eclipse Public License 2.0 which is available at
7* http://www.eclipse.org/legal/epl-2.0
8*
9* SPDX-License-Identifier: EPL-2.0
10*******************************************************************************/
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010011using BaSyx.Models.Core.AssetAdministrationShell.Identification;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010012using BaSyx.Models.Extensions;
13using BaSyx.Utils.ResultHandling;
14using Newtonsoft.Json;
15using System;
Constantin Ziesche08215502020-09-21 19:08:32 +020016using System.Collections;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010017using System.Collections.Generic;
18using System.Linq;
19
20namespace BaSyx.Models.Core.Common
21{
Constantin Ziesche08215502020-09-21 19:08:32 +020022
23 public class ElementContainer<TElement> : IElementContainer<TElement> where TElement : IReferable, IModelElement
Constantin Ziesche7b6d4792020-08-18 17:15:11 +020024 {
Constantin Ziesche08215502020-09-21 19:08:32 +020025 public const string PATH_SEPERATOR = "/";
26
27 private readonly List<IElementContainer<TElement>> _children;
28
29 public string IdShort { get; private set; }
30 public TElement Value { get; set; }
31 public string Path { get; set; }
32 public bool IsRoot => ParentContainer == null;
33 public IReferable Parent { get; set; }
34 public IElementContainer<TElement> ParentContainer { get; set; }
35
36 [JsonConstructor]
Constantin Ziesche0399d412020-09-24 14:31:15 +020037 public ElementContainer()
Constantin Ziesche7b6d4792020-08-18 17:15:11 +020038 {
Constantin Ziesche08215502020-09-21 19:08:32 +020039 _children = new List<IElementContainer<TElement>>();
Constantin Ziesche7b6d4792020-08-18 17:15:11 +020040 }
41
Constantin Ziesche0399d412020-09-24 14:31:15 +020042 public ElementContainer(IReferable parent) : this(parent, default, null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010043 { }
44
Constantin Ziesche08215502020-09-21 19:08:32 +020045 public ElementContainer(IReferable parent, TElement rootElement, IElementContainer<TElement> parentContainer)
46 {
47 _children = new List<IElementContainer<TElement>>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010048
Constantin Ziesche08215502020-09-21 19:08:32 +020049 Parent = parent;
50 ParentContainer = parentContainer;
51
52 IdShort = rootElement?.IdShort;
53 Value = rootElement;
54
55 if (ParentContainer != null && !string.IsNullOrEmpty(ParentContainer.Path))
56 {
57 Path = ParentContainer.Path + PATH_SEPERATOR + IdShort;
58 }
59 else
60 {
61 Path = IdShort;
62 }
63 }
64
65 public ElementContainer(IReferable parent, IEnumerable<TElement> list)
66 {
67 _children = new List<IElementContainer<TElement>>();
68
69 Parent = parent;
70 Value = default;
71 IdShort = null;
72
73 AddRange(list);
74 }
75 public TElement this[int i]
76 {
77 get
78 {
79 if (i < this.Count())
80 return _children[i].Value;
81 else
82 return default;
83 }
84 }
85
86 public TElement this[string idShortPath]
87 {
88 get
89 {
90 var child = _children.FirstOrDefault(c => c.IdShort == idShortPath);
91 if (child != null && child.Value != null)
92 return child.Value;
93 else
94 return default;
95 }
96 }
97
98 public IEnumerable<TElement> Values
99 {
100 get => _children.Select(s => s.Value);
101 }
102
103 public IEnumerable<IElementContainer<TElement>> Children
104 {
105 get => _children;
106 }
107
Constantin Ziesche0399d412020-09-24 14:31:15 +0200108 public int Count => _children.Count;
109
110 public bool IsReadOnly => false;
111
Constantin Ziesche08215502020-09-21 19:08:32 +0200112 public IResult<TElement> Create(TElement element)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100113 {
114 if (element == null)
115 return new Result<TElement>(new ArgumentNullException(nameof(element)));
Constantin Ziesche08215502020-09-21 19:08:32 +0200116 if (string.IsNullOrEmpty(element.IdShort))
117 return new Result<TElement>(new ArgumentNullException(nameof(element.IdShort)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100118
119 if (this[element.IdShort] == null)
Constantin Ziesche08215502020-09-21 19:08:32 +0200120 {
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100121 Add(element);
122 return new Result<TElement>(true, element);
123 }
124 else
125 return new Result<TElement>(false, new ConflictMessage(element.IdShort));
126 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200127
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100128 public IResult<T> Create<T>(T element) where T : class, TElement
129 {
130 if (element == null)
131 return new Result<T>(new ArgumentNullException(nameof(element)));
Constantin Ziesche08215502020-09-21 19:08:32 +0200132 if (string.IsNullOrEmpty(element.IdShort))
133 return new Result<T>(new ArgumentNullException(nameof(element.IdShort)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100134
135 if (this[element.IdShort] == null)
136 {
137 Add(element);
138 return new Result<T>(true, element);
139 }
140 else
141 return new Result<T>(false, new ConflictMessage(element.IdShort));
142 }
143
Constantin Ziesche08215502020-09-21 19:08:32 +0200144 public void Add(TElement element)
145 {
146 if (element == null)
147 throw new ArgumentNullException(nameof(element));
148 if (string.IsNullOrEmpty(element.IdShort))
149 throw new ArgumentNullException(nameof(element.IdShort));
150
151 if (this[element.IdShort] == null)
152 {
153 element.Parent = this.Parent;
154
155 IElementContainer<TElement> node;
156 if (element is IElementContainer<TElement> subElements)
157 {
158 subElements.Parent = this.Parent;
159 subElements.ParentContainer = this;
160 subElements.AppendRootPath(this.Path);
161 node = subElements;
162 }
163 else
164 node = new ElementContainer<TElement>(Parent, element, this);
165
166 this._children.Add(node);
167 }
168 }
169
170 public void AppendRootPath(string rootPath)
171 {
172 if (!string.IsNullOrEmpty(rootPath))
173 this.Path = rootPath + PATH_SEPERATOR + this.Path;
174
175 foreach (var child in _children)
176 {
177 if (child.HasChildren())
178 {
179 foreach (var subChild in child.Children)
180 {
181 subChild.AppendRootPath(rootPath);
182 }
183 }
184 if (!string.IsNullOrEmpty(rootPath))
185 child.Path = rootPath + PATH_SEPERATOR + child.Path;
186 }
187 }
188
189 public bool HasChildren()
190 {
191 if (_children == null)
192 return false;
193 else
194 {
195 if (_children.Count == 0)
196 return false;
197 else
198 return true;
199 }
200 }
201
202 public bool HasChild(string idShort)
203 {
204 if (_children == null || _children.Count == 0)
205 return false;
206 else
207 {
208 var child = _children.FirstOrDefault(c => c.IdShort == idShort);
209 if (child == null)
210 return false;
211 else
212 return true;
213 }
214 }
215
216 public bool HasChildPath(string idShortPath)
217 {
218 if (string.IsNullOrEmpty(idShortPath))
219 return false;
220
221 if (_children == null || _children.Count == 0)
222 return false;
223 else
224 {
225 if (idShortPath.Contains(PATH_SEPERATOR))
226 {
227 string[] splittedPath = idShortPath.Split(new char[] { PATH_SEPERATOR[0] }, StringSplitOptions.RemoveEmptyEntries);
228 if (!HasChild(splittedPath[0]))
229 return false;
230 else
231 {
232 var child = GetChild(splittedPath[0]);
233 return (child.HasChildPath(string.Join(PATH_SEPERATOR, splittedPath.Skip(1))));
234 }
235 }
236 else
237 return HasChild(idShortPath);
238 }
239 }
240
241 public IElementContainer<TElement> GetChild(string idShortPath)
242 {
243 if (string.IsNullOrEmpty(idShortPath))
244 return null;
245
246 if (_children == null || _children.Count == 0)
247 return null;
248 else
249 {
250 IElementContainer<TElement> superChild;
251 if (idShortPath.Contains(PATH_SEPERATOR))
252 {
253 string[] splittedPath = idShortPath.Split(new char[] { PATH_SEPERATOR[0] }, StringSplitOptions.RemoveEmptyEntries);
254 if (HasChild(splittedPath[0]))
255 {
256 var child = GetChild(splittedPath[0]);
257 superChild = child.GetChild(string.Join(PATH_SEPERATOR, splittedPath.Skip(1)));
258 }
259 else
260 superChild = null;
261 }
262 else
263 superChild = _children.FirstOrDefault(c => c.IdShort == idShortPath);
264
265 return superChild;
266 }
267 }
268
269 public IEnumerable<TElement> Flatten()
270 {
271 if (Value != null)
272 return new[] { Value }.Concat(_children.SelectMany(c => c.Flatten()));
273 else
274 return _children.SelectMany(c => c.Flatten());
275 }
276
277 public void Traverse(Action<TElement> action)
278 {
279 action(Value);
280 foreach (var child in _children)
281 child.Traverse(action);
282 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100283
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200284 public virtual IResult<IQueryableElementContainer<TElement>> RetrieveAll()
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100285 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200286 if (this.Count() == 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200287 return new Result<IQueryableElementContainer<TElement>>(true, new EmptyMessage());
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100288 else
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200289 return new Result<IQueryableElementContainer<TElement>>(true, this.AsQueryableElementContainer());
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100290 }
291
Constantin Ziesche0399d412020-09-24 14:31:15 +0200292 public virtual IResult<IQueryableElementContainer<T>> RetrieveAll<T>() where T : class, IReferable, IModelElement
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100293 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200294 if (this.Count() == 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200295 return new Result<IQueryableElementContainer<T>>(true, new EmptyMessage());
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100296 else
297 {
298 ElementContainer<T> container = new ElementContainer<T>();
299 foreach (var element in this)
300 {
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200301 T tElement = element.Cast<T>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100302 if (tElement != null)
303 container.Add(tElement);
304 }
305
Constantin Ziesche08215502020-09-21 19:08:32 +0200306 if(container.Count() > 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200307 return new Result<IQueryableElementContainer<T>>(true, container.AsQueryableElementContainer());
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100308 else
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200309 return new Result<IQueryableElementContainer<T>>(true, new EmptyMessage());
310 }
311 }
312
313 public IResult<IQueryableElementContainer<TElement>> RetrieveAll(Predicate<TElement> predicate)
314 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200315 if (this.Count() == 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200316 return new Result<IQueryableElementContainer<TElement>>(true, new EmptyMessage());
317 else
318 {
319 ElementContainer<TElement> container = new ElementContainer<TElement>();
Constantin Ziesche08215502020-09-21 19:08:32 +0200320 var elements = Values.ToList().FindAll(predicate);
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200321 if(elements?.Count() > 0)
322 container.AddRange(elements);
323
Constantin Ziesche08215502020-09-21 19:08:32 +0200324 if (container.Count() > 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200325 return new Result<IQueryableElementContainer<TElement>>(true, container.AsQueryableElementContainer());
326 else
327 return new Result<IQueryableElementContainer<TElement>>(true, new EmptyMessage());
328 }
329 }
330
Constantin Ziesche0399d412020-09-24 14:31:15 +0200331 public virtual IResult<IQueryableElementContainer<T>> RetrieveAll<T>(Predicate<T> predicate) where T : class, IReferable, IModelElement
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200332 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200333 if (this.Count() == 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200334 return new Result<IQueryableElementContainer<T>>(true, new EmptyMessage());
335 else
336 {
337 ElementContainer<T> container = new ElementContainer<T>();
338 foreach (var element in this)
339 {
340 T tElement = element.Cast<T>();
341 if (tElement != null)
342 container.Add(tElement);
343 }
344
Constantin Ziesche08215502020-09-21 19:08:32 +0200345 if (container.Count() > 0)
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200346 return new Result<IQueryableElementContainer<T>>(true, container.AsQueryableElementContainer());
347 else
348 return new Result<IQueryableElementContainer<T>>(true, new EmptyMessage());
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100349 }
350 }
351
Constantin Ziesche08215502020-09-21 19:08:32 +0200352 public virtual IResult<TElement> Retrieve(string idShortPath)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100353 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200354 if (string.IsNullOrEmpty(idShortPath))
355 return new Result<TElement>(new ArgumentNullException(nameof(idShortPath)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100356
Constantin Ziesche08215502020-09-21 19:08:32 +0200357 var child = GetChild(idShortPath);
358 if (child != null)
359 return new Result<TElement>(true, child.Value);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100360 else
361 return new Result<TElement>(false, new NotFoundMessage());
362 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200363 public IResult<T> Retrieve<T>(string idShortPath) where T : class, TElement
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100364 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200365 if (string.IsNullOrEmpty(idShortPath))
366 return new Result<T>(new ArgumentNullException(nameof(idShortPath)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100367
Constantin Ziesche08215502020-09-21 19:08:32 +0200368 T element = GetChild(idShortPath)?.Value?.Cast<T>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100369 if (element != null)
370 return new Result<T>(true, element);
371 else
372 return new Result<T>(false, new NotFoundMessage());
373 }
374
Constantin Ziesche08215502020-09-21 19:08:32 +0200375 public virtual IResult<TElement> CreateOrUpdate(string idShortPath, TElement element)
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100376 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200377 if (string.IsNullOrEmpty(idShortPath))
378 return new Result<TElement>(new ArgumentNullException(nameof(idShortPath)));
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100379 if (element == null)
380 return new Result<TElement>(new ArgumentNullException(nameof(element)));
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200381
Constantin Ziesche08215502020-09-21 19:08:32 +0200382 var child = GetChild(idShortPath);
383 if (child != null)
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100384 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200385 child.Value = element;
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100386 return new Result<TElement>(true, element);
387 }
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200388 else if (idShortPath.Contains(PATH_SEPERATOR))
389 {
390 string parentPath = idShortPath.Substring(0, idShortPath.LastIndexOf('/'));
391 var parent = GetChild(parentPath);
392 if (parent != null)
393 return parent.Create(element);
394 else
395 return new Result<TElement>(false, new NotFoundMessage($"Parent element {parentPath} not found"));
396 }
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100397 else
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200398 return this.Create(element);
Constantin Ziesche6c02c5d2020-03-05 09:12:24 +0100399 }
400
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100401
Constantin Ziesche08215502020-09-21 19:08:32 +0200402 public virtual IResult<TElement> Update(string idShortPath, TElement element)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100403 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200404 if (string.IsNullOrEmpty(idShortPath))
405 return new Result<TElement>(new ArgumentNullException(nameof(idShortPath)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100406 if (element == null)
407 return new Result<TElement>(new ArgumentNullException(nameof(element)));
408
Constantin Ziesche08215502020-09-21 19:08:32 +0200409 var child = GetChild(idShortPath);
410 if (child != null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100411 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200412 child.Value = element;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100413 return new Result<TElement>(true, element);
414 }
415 return new Result<TElement>(false, new NotFoundMessage());
416 }
417
Constantin Ziesche08215502020-09-21 19:08:32 +0200418 public virtual IResult Delete(string idShortPath)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100419 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200420 if (string.IsNullOrEmpty(idShortPath))
421 return new Result<TElement>(new ArgumentNullException(nameof(idShortPath)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100422
Constantin Ziesche08215502020-09-21 19:08:32 +0200423 var child = GetChild(idShortPath);
424 if (child != null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100425 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200426 child.ParentContainer.Remove(child.IdShort);
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200427 return new Result(true);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100428 }
429 return new Result(false, new NotFoundMessage());
430 }
431
Constantin Ziesche08215502020-09-21 19:08:32 +0200432 public void Remove(string idShort)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100433 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200434 _children.RemoveAll(c => c.IdShort == idShort);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100435 }
436
Constantin Ziesche08215502020-09-21 19:08:32 +0200437 public void AddRange(IEnumerable<TElement> collection)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100438 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200439 foreach (var item in collection)
440 {
441 Add(item);
442 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100443 }
444
Constantin Ziesche08215502020-09-21 19:08:32 +0200445 public IEnumerator<TElement> GetEnumerator()
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100446 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200447 return Values.GetEnumerator();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100448 }
449
Constantin Ziesche08215502020-09-21 19:08:32 +0200450 IEnumerator IEnumerable.GetEnumerator()
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100451 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200452 return Values.GetEnumerator();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100453 }
Constantin Ziesche0399d412020-09-24 14:31:15 +0200454
455 public void Clear()
456 {
457 _children.Clear();
458 }
459
460 public bool Contains(TElement item)
461 {
462 return this[item.IdShort] != null;
463 }
464
465 public void CopyTo(TElement[] array, int arrayIndex)
466 {
467 for (int i = arrayIndex; i < array.Length && i < _children.Count; i++)
468 {
469 array[i] = _children[i].Value;
470 }
471 }
472
473 public bool Remove(TElement item)
474 {
475 var removed = _children.RemoveAll(c => c.IdShort == item.IdShort);
476 if (removed > 0)
477 return true;
478 else
479 return false;
480 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100481 }
482}