1 // =================================
  2 // Copyright (c) 2025 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 
  9 namespace System.Xml
 10 {
 11     public class Document : ParentNode
 12     {
 13         public Document() : this(System.Lex.Span()-1)
 14         {
 15         }
 16         public Document(const System.Lex.Span& span_int fileIndex_) : base(NodeKind.documentNodespan_fileIndex_"document")
 17         {
 18         }
 19         public Element* DocumentElement() const
 20         {
 21             return documentElement;
 22         }
 23         public bool XmlStandalone() const
 24         {
 25             return xmlStandalone;
 26         }
 27         public void SetXmlStandalone(bool xmlStandalone_)
 28         {
 29             xmlStandalone = xmlStandalone_;
 30         }
 31         public const string& XmlVersion() const
 32         {
 33             return xmlVersion;
 34         }
 35         public void SetXmlVersion(const string& xmlVersion_)
 36         {
 37             xmlVersion = xmlVersion_;
 38         }
 39         public const string& XmlEncoding() const
 40         {
 41             return xmlEncoding;
 42         }
 43         public void SetXmlEncoding(const string& xmlEncoding_)
 44         {
 45             xmlEncoding = xmlEncoding_;
 46         }
 47         public const Map<stringElement*>& Index() const
 48         {
 49             return index;
 50         }
 51         public Map<stringElement*>& Index()
 52         {
 53             return index;
 54         }
 55         public Element* GetElementById(const string& elementId) const
 56         {
 57             if (!indexValid)
 58             {
 59                 index.Clear();
 60                 BuildIndex(this);
 61                 indexValid = true;
 62             }
 63             auto it = index.Find(elementId);
 64             if (it != index.End())
 65             {
 66                 return it->second;
 67             }
 68             else
 69             {
 70                 return null;
 71             }
 72         }
 73         public override void AppendChild(Node* child)
 74         {
 75             base->AppendChild(child);
 76             if (child->IsElementNode())
 77             {
 78                 documentElement = cast<Element*>(child);
 79             }
 80         }
 81         public override void InsertBefore(Node* newChildNode* refChild)
 82         {
 83             base->InsertBefore(newChildrefChild);
 84             if (newChild->IsElementNode())
 85             {
 86                 documentElement = cast<Element*>(newChild);
 87             }
 88         }
 89         public override UniquePtr<Node> RemoveChild(Node* child)
 90         {
 91             UniquePtr<Node> removedChild = base->RemoveChild(child);
 92             if (removedChild.Get() == documentElement)
 93             {
 94                 documentElement = null;
 95             }
 96             return removedChild;
 97         }
 98         public override UniquePtr<Node> ReplaceChild(Node* newChildNode* oldChild)
 99         {
100             if (newChild->IsElementNode())
101             {
102                 UniquePtr<Node> removed = RemoveChild(oldChild);
103                 AppendChild(newChild);
104                 return removed;
105             }
106             else
107             {
108                 return base->ReplaceChild(newChildoldChild);
109             }
110         }
111         public override void Accept(Visitor& visitor)
112         {
113             visitor.BeginVisit(*this);
114             base->Accept(visitor);
115             visitor.EndVisit(*this);
116         }
117         [nodiscard]
118         public override Result<bool> Write(System.Text.CodeFormatter& formatter)
119         {
120             if (formatter.Error())
121             {
122                 return Result<bool>(ErrorId(formatter.GetErrorId()));
123             }
124             if (!xmlVersion.IsEmpty() && !xmlEncoding.IsEmpty())
125             {
126                 formatter << "<?xml version=\"" << xmlVersion << "\" encoding=\"" << xmlEncoding << "\"?>" << endl();
127             }
128             auto result = base->Write(formatter);
129             if (result.Error())
130             {
131                 return Result<bool>(ErrorId(result.GetErrorId()));
132             }
133             if (formatter.Error())
134             {
135                 return Result<bool>(ErrorId(formatter.GetErrorId()));
136             }
137             return Result<bool>(true);
138         }
139         public override Node* Clone(bool deep) const
140         {
141             Document* clone = new Document(Span()FileIndex());
142             if (deep)
143             {
144                 clone->AppendChild(documentElement->Clone(deep));
145             }
146             return clone;
147         }
148         public void InvalidateIndex()
149         {
150             indexValid = false;
151         }
152         private Element* documentElement;
153         private bool indexValid;
154         private bool xmlStandalone;
155         private string xmlVersion;
156         private string xmlEncoding;
157         private Map<stringElement*> index;
158     }
159 
160     public UniquePtr<Document> MakeDocument()
161     {
162         return UniquePtr<Document>(new Document());
163     }
164 }