251 lines
8.5 KiB
C#
251 lines
8.5 KiB
C#
namespace SessionZero.Data;
|
|
|
|
[SzfObject(SzfObjectType.Dataset, "dataset")]
|
|
public class Dataset : SzfObject
|
|
{
|
|
public string DatasetType { get; set; } = string.Empty;
|
|
public string ImageUrl { get; set; } = string.Empty;
|
|
|
|
// Collection of entries within this dataset
|
|
public List<DatasetEntry> Entries { get; set; } = [];
|
|
|
|
// Additional metadata fields for .szf compatibility
|
|
public Dictionary<string, object> Metadata { get; set; } = new();
|
|
|
|
public override SzfObjectType ObjectType => SzfObjectType.Dataset;
|
|
|
|
public override void PopulateFromMetadata(Dictionary<string, SzfField> metadata)
|
|
{
|
|
// Call base method to populate common fields
|
|
base.PopulateFromMetadata(metadata);
|
|
|
|
// Populate dataset-specific fields
|
|
if (metadata.TryGetValue("Type", out var typeField))
|
|
DatasetType = typeField.Value?.ToString() ?? string.Empty;
|
|
|
|
if (metadata.TryGetValue("ImageUrl", out var imageField))
|
|
ImageUrl = imageField.Value?.ToString() ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses sections specific to the Dataset object, such as entries and their subsections.
|
|
/// This method is called by the SzfParser to populate Dataset-specific data.
|
|
/// </summary>
|
|
/// <param name="sections">A list of all parsed sections from the SZF file.</param>
|
|
public override void ParseSections(List<SzfSection> sections)
|
|
{
|
|
// Dictionary to hold DatasetEntry objects by their name for easy lookup
|
|
var entriesByName = new Dictionary<string, DatasetEntry>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
// First pass: Identify and populate top-level DatasetEntry objects
|
|
foreach (var szfSection in sections)
|
|
{
|
|
if (szfSection.Name.StartsWith("Entry:", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var entryName = szfSection.Name.Substring("Entry:".Length).Trim();
|
|
if (string.IsNullOrEmpty(entryName)) continue;
|
|
|
|
var newEntry = new DatasetEntry { Name = entryName };
|
|
foreach (var field in szfSection.Fields)
|
|
{
|
|
newEntry.Fields.Add(ConvertToDatasetField(field));
|
|
}
|
|
|
|
Entries.Add(newEntry);
|
|
entriesByName[entryName] = newEntry;
|
|
}
|
|
}
|
|
|
|
// Second pass: Populate sections and subsections for each entry
|
|
foreach (var szfSection in sections)
|
|
{
|
|
// We are looking for sections like "Entry.EntryName.SectionName" or "Entry.EntryName.SectionName.SubSectionName"
|
|
if (!szfSection.Name.StartsWith("Entry.", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
// Split the section name by '.' to identify parts
|
|
var nameParts = szfSection.Name.Split('.');
|
|
|
|
// Ensure it's a section of an entry (e.g., "Entry.EntryName.Section")
|
|
if (nameParts.Length < 3 || !nameParts[0].Equals("Entry", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
var entryName = nameParts[1];
|
|
if (!entriesByName.TryGetValue(entryName, out var targetEntry)) continue; // Entry not found, skip
|
|
|
|
// We need to build the hierarchy of DatasetSection objects
|
|
DatasetSection? currentParentSection = null;
|
|
List<DatasetSection> currentSectionList = targetEntry.Sections;
|
|
|
|
for (int i = 2; i < nameParts.Length; i++) // Start from the first section name after "Entry.EntryName"
|
|
{
|
|
var sectionNamePart = nameParts[i];
|
|
var existingSection = currentSectionList.FirstOrDefault(s =>
|
|
s.Name.Equals(sectionNamePart, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (existingSection == null)
|
|
{
|
|
// Create new section
|
|
var newSection = new DatasetSection { Name = sectionNamePart };
|
|
currentSectionList.Add(newSection);
|
|
currentParentSection = newSection;
|
|
}
|
|
else
|
|
{
|
|
currentParentSection = existingSection;
|
|
}
|
|
|
|
// If this is the last part of the section name, populate its fields
|
|
if (i == nameParts.Length - 1)
|
|
{
|
|
foreach (var field in szfSection.Fields)
|
|
{
|
|
currentParentSection.Fields.Add(ConvertToDatasetField(field));
|
|
}
|
|
}
|
|
|
|
// Move to the next level down in the hierarchy
|
|
currentSectionList = currentParentSection.Subsections;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert SzfField to DatasetField
|
|
/// </summary>
|
|
private DatasetField ConvertToDatasetField(SzfField szfField)
|
|
{
|
|
return new DatasetField
|
|
{
|
|
Name = szfField.Name,
|
|
Type = ParseDatasetFieldType(szfField.Type),
|
|
Value = szfField.Value
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse DatasetFieldType from string
|
|
/// </summary>
|
|
private DatasetFieldType ParseDatasetFieldType(string typeString)
|
|
{
|
|
return typeString.ToLower() switch
|
|
{
|
|
"text" => DatasetFieldType.Text,
|
|
"text-field" => DatasetFieldType.TextField,
|
|
"number" => DatasetFieldType.Number,
|
|
"bool" => DatasetFieldType.Boolean,
|
|
"group" => DatasetFieldType.Group,
|
|
"calculated" => DatasetFieldType.Calculated,
|
|
"system" => DatasetFieldType.System,
|
|
"dataset-reference" => DatasetFieldType.DatasetReference,
|
|
"dataset-type" => DatasetFieldType.DatasetType,
|
|
"dataset-reference-multiple" => DatasetFieldType.DatasetReferenceMultiple,
|
|
"dataset-type-multiple" => DatasetFieldType.DatasetTypeMultiple,
|
|
_ => DatasetFieldType.Text
|
|
};
|
|
}
|
|
|
|
|
|
public override SzfValidationResult Validate()
|
|
{
|
|
var result = base.Validate();
|
|
|
|
if (string.IsNullOrWhiteSpace(DatasetType))
|
|
result.AddError("DatasetType is required");
|
|
|
|
// Validate entries
|
|
var entryNames = new HashSet<string>();
|
|
foreach (var entry in Entries)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(entry.Name))
|
|
{
|
|
result.AddError("All entries must have a name");
|
|
continue;
|
|
}
|
|
|
|
if (!entryNames.Add(entry.Name))
|
|
result.AddError($"Duplicate entry name: {entry.Name}");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public class DatasetEntry
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public List<DatasetField> Fields { get; set; } = [];
|
|
public List<DatasetSection> Sections { get; set; } = [];
|
|
}
|
|
|
|
public class DatasetSection
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public List<DatasetField> Fields { get; set; } = [];
|
|
public List<DatasetSection> Subsections { get; set; } = [];
|
|
}
|
|
|
|
public class DatasetField
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public DatasetFieldType Type { get; set; }
|
|
public object? Value { get; set; } = null;
|
|
public string? Description { get; set; }
|
|
public bool IsRequired { get; set; } = false;
|
|
public object? DefaultValue { get; set; }
|
|
|
|
// For calculated fields
|
|
public string? Formula { get; set; }
|
|
|
|
// For dataset reference fields
|
|
public string? ReferencedDatasetId { get; set; }
|
|
public string? ReferencedDatasetType { get; set; }
|
|
public bool AllowMultiple { get; set; } = false;
|
|
|
|
// For group fields
|
|
public List<DatasetField> GroupFields { get; set; } = [];
|
|
}
|
|
|
|
public enum DatasetFieldType
|
|
{
|
|
Text,
|
|
TextField,
|
|
Number,
|
|
Boolean,
|
|
Group,
|
|
Calculated,
|
|
System,
|
|
DatasetReference,
|
|
DatasetType,
|
|
DatasetReferenceMultiple,
|
|
DatasetTypeMultiple
|
|
}
|
|
|
|
// Supporting classes for dataset management
|
|
public class DatasetReference
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public Guid Guid { get; set; }
|
|
public string Version { get; set; } = string.Empty;
|
|
|
|
public override string ToString() => $"{Name}|{Guid}|{Version}";
|
|
|
|
public static DatasetReference? Parse(string reference)
|
|
{
|
|
var parts = reference.Split('|');
|
|
if (parts.Length != 3 || !Guid.TryParse(parts[1], out var id))
|
|
return null;
|
|
|
|
return new DatasetReference
|
|
{
|
|
Name = parts[0],
|
|
Guid = id,
|
|
Version = parts[2]
|
|
};
|
|
}
|
|
}
|
|
|
|
public class DatasetValidationResult
|
|
{
|
|
public bool IsValid { get; set; }
|
|
public List<string> Errors { get; set; } = [];
|
|
public List<string> Warnings { get; set; } = [];
|
|
} |