1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 
  9 namespace System.Xml.Serialization
 10 {
 11     public class XmlContainer
 12     {
 13         public XmlContainer()
 14         {
 15         }
 16         public virtual ~XmlContainer()
 17         {
 18             Clear();
 19         }
 20         public virtual void SetRootObjectId(const Uuid& objectId)
 21         {
 22         }
 23         public inline long Count() const
 24         {
 25             return objectProxyMap.Count();
 26         }
 27         public inline bool IsEmpty() const
 28         {
 29             return objectProxyMap.IsEmpty();
 30         }
 31         public void Clear()
 32         {
 33             for (const Pair<void*XmlSerializableProxy*>& p : objectProxyMap)
 34             {
 35                 delete p.second;
 36             }
 37             idProxyMap.Clear();
 38             objectProxyMap.Clear();
 39 
 40         }
 41         [nodiscard]
 42         public Result<bool> Add(XmlSerializable xmlSerializable)
 43         {
 44             XmlSerializableProxy* prev = Get(xmlSerializable.ObjectId());
 45             if (prev != null)
 46             {
 47                 auto objectIdStrResult = ToString(prev->ObjectId());
 48                 if (objectIdStrResult.Error()) return Result<bool>(ErrorId(objectIdStrResult.GetErrorId()));
 49                 string objectIdStr = Rvalue(objectIdStrResult.Value());
 50                 int errorId = AllocateError("object \'" + objectIdStr + "\' already added to XML container");
 51                 return Result<bool>(ErrorId(errorId));
 52             }
 53             XmlSerializableProxy* proxy = new XmlSerializableProxy(xmlSerializable);
 54             idProxyMap[proxy->ObjectId()] = proxy;
 55             objectProxyMap[proxy->Object()] = proxy;
 56             proxy->SetContainer(this);
 57             return Result<bool>(true);
 58         }
 59         public XmlSerializableProxy* Get(const Uuid& objectId) const
 60         {
 61             auto it = idProxyMap.Find(objectId);
 62             if (it != idProxyMap.End())
 63             {
 64                 return it->second;
 65             }
 66             else
 67             {
 68                 return null;
 69             }
 70         }
 71         public void Remove(const Uuid& objectId)
 72         {
 73             XmlSerializableProxy* proxy = Get(objectId);
 74             if (proxy != null)
 75             {
 76                 objectProxyMap.Remove(proxy->Object());
 77                 idProxyMap.Remove(objectId);
 78                 delete proxy;
 79             }
 80         }
 81         public XmlSerializableProxy* GetProxy(void* object)
 82         {
 83             auto it = objectProxyMap.Find(object);
 84             if (it != objectProxyMap.End())
 85             {
 86                 XmlSerializableProxy* proxy = it->second;
 87                 return proxy;
 88             }
 89             else
 90             {
 91                 return null;
 92             }
 93         }
 94         public List<XmlSerializableProxy*> GetProxies() const
 95         {
 96             List<XmlSerializableProxy*> proxies;
 97             for (const Pair<void*XmlSerializableProxy*>& p : objectProxyMap)
 98             {
 99                 if (p.second != null)
100                 {
101                     proxies.Add(p.second);
102                 }
103             }
104             return proxies;
105         }
106         [nodiscard]
107         public Result<bool> AddToBundle(XmlBundle& bundleXmlBundleKind kindint hopsXmlSerializable intfHashSet<Uuid>& addedSet)
108         {
109             if (intf.ObjectId() == Uuid())
110             {
111                 return Result<bool>(false);
112             }
113             if (addedSet.Find(intf.ObjectId()) != addedSet.End())
114             {
115                 return Result<bool>(false);
116             }
117             auto addResult = bundle.Add(intf);
118             if (addResult.Error()) return addResult;
119             addedSet.Insert(intf.ObjectId());
120             if (kind == XmlBundleKind.deep && (hops == -1 || hops > 0))
121             {
122                 List<XmlPtrBase*> ptrs = intf.GetPtrs();
123                 for (XmlPtrBase* ptr : ptrs)
124                 {
125                     if (ptr->TargetObjectId() != Uuid())
126                     {
127                         XmlSerializableProxy* target = Get(ptr->TargetObjectId());
128                         if (target != null)
129                         {
130                             int nextHops = -1;
131                             if (hops > 0)
132                             {
133                                 nextHops = hops - 1;
134                             }
135                             auto addResult = AddToBundle(bundlekindnextHopstarget->Interface()addedSet);
136                             if (addResult.Error()) return addResult;
137                         }
138                         else
139                         {
140                             XmlSerializable intf = ptr->Interface();
141                             XmlContainer* container = intf.Container();
142                             if (container != null)
143                             {
144                                 target = container->Get(ptr->TargetObjectId());
145                                 if (target != null)
146                                 {
147                                     int nextHops = -1;
148                                     if (hops > 0)
149                                     {
150                                         nextHops = hops - 1;
151                                     }
152                                     auto addResult = container->AddToBundle(bundlekindnextHopsintfaddedSet);
153                                     if (addResult.Error()) return addResult;
154                                 }
155                             }
156                         }
157                     }
158                 }
159             }
160             return Result<bool>(true);
161         }
162         public Result<XmlBundle> CreateBundle(void* object)
163         {
164             return CreateBundle(objectXmlBundleKind.shallow);
165         }
166         public Result<XmlBundle> CreateBundle(void* objectXmlBundleKind kind)
167         {
168             return CreateBundle(objectkind-1);
169         }
170         public Result<XmlBundle> CreateBundle(void* objectXmlBundleKind kindint hops)
171         {
172             HashSet<Uuid> addedSet;
173             XmlBundle bundle;
174             XmlSerializableProxy* proxy = GetProxy(object);
175             if (proxy != null)
176             {
177                 bundle.SetRootObjectId(proxy->ObjectId());
178                 XmlSerializable intf = proxy->Interface();
179                 auto addResult = AddToBundle(bundlekindhopsintfaddedSet);
180                 if (addResult.Error()) return Result<XmlBundle>(ErrorId(addResult.GetErrorId()));
181             }
182             return Result<XmlBundle>(Rvalue(bundle));
183         }
184         public HashMap<UuidXmlSerializableProxy*> idProxyMap;
185         public HashMap<void*XmlSerializableProxy*> objectProxyMap;
186     }
187 
188     public Result<bool> Add<T>(T* objectXmlContainer* container)
189     {
190         XmlSerializable xmlSerializable(*object);
191         return container->Add(xmlSerializable);
192     }
193 
194     public Result<bool> AddOrReplace<T>(T* objectXmlContainer* container)
195     {
196         XmlSerializable xmlSerializable(*object);
197         container->Remove(xmlSerializable.ObjectId());
198         return container->Add(xmlSerializable);
199     }
200 
201     public void RemoveFromContainer<T>(T* object)
202     {
203         XmlSerializable xmlSerializable(*object);
204         XmlContainer* container = xmlSerializable.Container();
205         if (container != null)
206         {
207             container->Remove(xmlSerializable.ObjectId());
208         }
209     }
210 }