// Copyright (C) Stichting Deltares 2025. All rights reserved.
//
// This file is part of the application DAM - UI.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Deltares.Standard.IO.DtoAssembler;
namespace Deltares.Standard;
///
/// Base class for a data transfer collection assembler
///
/// The type of class to be assembled
public abstract class DtoCollectionAssembler : IDtoCollectionAssembler
where TDomainObject : new()
{
///
/// Holds a reference to the entity assembler
///
private readonly DtoAssembler entityAssembler;
public DtoCollectionAssembler(DtoAssembler entityAssembler, string elementName)
{
this.entityAssembler = entityAssembler;
ElementName = elementName;
}
///
/// Creates a domain object collection from an xml document
///
///
///
public IEnumerable CreateDomainObjectCollection(string xmlString)
{
XDocument doc = XDocument.Parse(xmlString);
// assemble the collection
return CreateDomainObjectCollection(doc);
}
///
/// Creates a domain object collection from an xml document
///
///
///
public IEnumerable CreateDomainObjectCollection(XDocument doc)
{
IEnumerable dto = from x in doc.Descendants()
where x.Name.LocalName == EntityAssembler.ElementName && x.Parent.Name.LocalName == ElementName
select x;
// assemble the collection
return CreateDomainObjectCollection(dto);
}
///
///
///
///
///
public IEnumerable CreateDomainObjectCollection(IEnumerable dtoObjColl)
{
return dtoObjColl.ToDomainObjectIterator(entityAssembler);
}
///
///
///
///
///
public XElement CreateDataTransferObject(IEnumerable domainObjColl, XNamespace elementNamespace)
{
XElement el = CreateDataTransferObject(domainObjColl);
var nel = new XElement(elementNamespace + ElementName);
el.Name = nel.Name;
return el;
}
#region IDtoCollectionAssembler Members
///
/// Gets the entity assembler
///
public IDtoAssembler EntityAssembler
{
get
{
return entityAssembler;
}
}
///
/// Gets or sets the xml element name
///
public string ElementName { get; }
///
///
///
///
///
public virtual IEnumerable CreateDomainObjectCollection(XElement dtoSequenceElement)
{
IEnumerable dto = from x in dtoSequenceElement.Descendants()
where x.Name.LocalName == EntityAssembler.ElementName && x.Parent.Name.LocalName == ElementName
select x;
return dto.ToDomainObjectIterator(entityAssembler);
}
///
///
///
///
///
public virtual XElement CreateDataTransferObject(IEnumerable domainObjColl)
{
if (!ElementName.HasValidStringValue())
{
throw new DtoAssemblerException("There is no element name specified");
}
if (entityAssembler == null)
{
// TODO: need to support serialization based on reflection
}
// is there a schema attached to the assembler so we can
// validate the collection?
XDocument schema = entityAssembler.Schema;
if (schema != null)
{
if (entityAssembler == null)
{
// TODO: need to support serialization based on reflection
}
else
{
// get the collection rules (min and max requirements) (if any)
var collRules = from x in schema.Descendants()
where x.Name.LocalName == "element" && x.Attribute("name").Value == entityAssembler.ElementName
select new
{
MinOccurs = x.AttributeAs("minOccurs") == "unbounded" ? 0 : x.AttributeAs("minOccurs"),
MaxOccurs = x.AttributeAs("maxOccurs") == "unbounded" ? -1 : x.AttributeAs("maxOccurs")
};
if (collRules.Any())
{
var rules = collRules.Single();
// validate the min and max values of the collection according to the xsd
int count = domainObjColl.Count();
if (domainObjColl == null || (count == 0 && rules.MinOccurs > 0)
|| (count > 0 & rules.MaxOccurs >= 0 && count > rules.MaxOccurs))
{
throw new CollectionRequirementsNotSatisfiedException(ElementName, EntityAssembler.ElementName, domainObjColl);
}
}
}
}
else if (domainObjColl == null)
{
return null; // Use empty sequence instead?
}
return new XElement(ElementName, domainObjColl.ToDtoIterator(entityAssembler).ToArray());
}
#endregion
}