1 // =================================
  2 // Copyright (c) 2021 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 nothrow XmlContainer()
 14         {
 15         }
 16         public virtual ~XmlContainer()
 17         {
 18             Clear();
 19         }
 20         public virtual nothrow void SetRootObjectId(const Uuid& objectId)
 21         {
 22         }
 23         public nothrow long Count() const
 24         {
 25             return objectProxyMap.Count();
 26         }
 27         public nothrow bool IsEmpty() const
 28         {
 29             return objectProxyMap.IsEmpty();
 30         }
 31         public nothrow 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         public void Add(XmlSerializable xmlSerializable)
 42         {
 43             XmlSerializableProxy* prev = Get(xmlSerializable.ObjectId());
 44             if (prev != null)
 45             {
 46                 throw XmlSerializationException("object '" + ToString(prev->ObjectId()) + "' already added to XML container");
 47             }
 48             XmlSerializableProxy* proxy = new XmlSerializableProxy(xmlSerializable);
 49             idProxyMap[proxy->ObjectId()] = proxy;
 50             objectProxyMap[proxy->Object()] = proxy;
 51             proxy->SetContainer(this);
 52         }
 53         public nothrow XmlSerializableProxy* Get(const Uuid& objectId) const
 54         {
 55             HashMap<UuidXmlSerializableProxy*>.ConstIterator it = idProxyMap.CFind(objectId);
 56             if (it != idProxyMap.CEnd())
 57             {
 58                 return it->second;
 59             }
 60             else
 61             {
 62                 return null;
 63             }
 64         }
 65         public void Remove(const Uuid& objectId)
 66         {
 67             XmlSerializableProxy* proxy = Get(objectId);
 68             if (proxy != null)
 69             {
 70                 objectProxyMap.Remove(proxy->Object());
 71                 idProxyMap.Remove(objectId);
 72                 delete proxy;
 73             }
 74         }
 75         public nothrow XmlSerializableProxy* GetProxy(void* object)
 76         {
 77             HashMap<void*XmlSerializableProxy*>.ConstIterator it = objectProxyMap.CFind(object);
 78             if (it != objectProxyMap.CEnd())
 79             {
 80                 XmlSerializableProxy* proxy = it->second;
 81                 return proxy;
 82             }
 83             else
 84             {
 85                 return null;
 86             }
 87         }
 88         public List<XmlSerializableProxy*> GetProxies() const
 89         {
 90             List<XmlSerializableProxy*> proxies;
 91             for (const Pair<void*XmlSerializableProxy*>& p : objectProxyMap)
 92             {
 93                 if (p.second != null)
 94                 {
 95                     proxies.Add(p.second);
 96                 }
 97             }
 98             return proxies;
 99         }
100         public void AddToBundle(XmlBundle& bundleXmlBundleKind kindint hopsXmlSerializable intfHashSet<Uuid>& addedSet)
101         {
102             if (intf.ObjectId() == Uuid())
103             {
104                 return;
105             }
106             if (addedSet.CFind(intf.ObjectId()) != addedSet.CEnd())
107             {
108                 return;
109             }
110             bundle.Add(intf);
111             addedSet.Insert(intf.ObjectId());
112             if (kind == XmlBundleKind.deep && (hops == -1 || hops > 0))
113             {
114                 List<XmlPtrBase*> ptrs = intf.GetPtrs();
115                 for (XmlPtrBase* ptr : ptrs)
116                 {
117                     if (ptr->TargetObjectId() != Uuid())
118                     {
119                         XmlSerializableProxy* target = Get(ptr->TargetObjectId());
120                         if (target != null)
121                         {
122                             int nextHops = -1;
123                             if (hops > 0)
124                             {
125                                 nextHops = hops - 1;
126                             }
127                             AddToBundle(bundlekindnextHopstarget->Interface()addedSet);
128                         }
129                         else
130                         {
131                             XmlSerializable intf = ptr->Interface();
132                             XmlContainer* container = intf.Container();
133                             if (container != null)
134                             {
135                                 target = container->Get(ptr->TargetObjectId());
136                                 if (target != null)
137                                 {
138                                     int nextHops = -1;
139                                     if (hops > 0)
140                                     {
141                                         nextHops = hops - 1;
142                                     }
143                                     container->AddToBundle(bundlekindnextHopsintfaddedSet);
144                                 }
145                             }
146                         }
147                     }
148                 }
149             }
150         }
151         public XmlBundle CreateBundle(void* object)
152         {
153             return CreateBundle(objectXmlBundleKind.shallow);
154         }
155         public XmlBundle CreateBundle(void* objectXmlBundleKind kind)
156         {
157             return CreateBundle(objectkind-1);
158         }
159         public XmlBundle CreateBundle(void* objectXmlBundleKind kindint hops)
160         {
161             HashSet<Uuid> addedSet;
162             XmlBundle bundle;
163             XmlSerializableProxy* proxy = GetProxy(object);
164             if (proxy != null)
165             {
166                 bundle.SetRootObjectId(proxy->ObjectId());
167                 XmlSerializable intf = proxy->Interface();
168                 AddToBundle(bundlekindhopsintfaddedSet);
169             }
170             return bundle;
171         }
172         public HashMap<UuidXmlSerializableProxy*> idProxyMap;
173         public HashMap<void*XmlSerializableProxy*> objectProxyMap;
174     }
175 
176     public void Add<T>(T* objectXmlContainer* container)
177     {
178         XmlSerializable xmlSerializable(*object);
179         container->Add(xmlSerializable);
180     }
181 
182     public void AddOrReplace<T>(T* objectXmlContainer* container)
183     {
184         XmlSerializable xmlSerializable(*object);
185         container->Remove(xmlSerializable.ObjectId());
186         container->Add(xmlSerializable);
187     }
188 
189     public void RemoveFromContainer<T>(T* object)
190     {
191         XmlSerializable xmlSerializable(*object);
192         XmlContainer* container = xmlSerializable.Container();
193         if (container != null)
194         {
195             container->Remove(xmlSerializable.ObjectId());
196         }
197     }
198 }
199