using SzCore.DataObjects; namespace SzCore; public class SzDataHandler { private readonly Dictionary _loadedDatasets = []; private readonly Dictionary _loadedTemplates = []; public SzDataHandler() { } public void ClearCache() { _loadedDatasets.Clear(); _loadedTemplates.Clear(); } #region Datasets public async Task> SaveDatasetAsync(SzDataset dataset, CancellationToken ct = default) { var datasetPath = Path.Combine(SZ.LocalFileManager.DatasetsPath, dataset.Id, "dataset.json"); try { var json = SZ.Parser.SerializeDatasetToJson(dataset); var evalResult = await SZ.Evaluator.EvaluateDatasetAsync(dataset); if (!evalResult.IsSuccess) return SzResult.Failure($"Could not save dataset, evaluation failed: {evalResult.Error!}"); var success = await SZ.LocalFileManager.SaveFileAsync(datasetPath, json, ct); return success ? SzResult.Success(true) : SzResult.Failure("Failed to write dataset file."); } catch (Exception e) { SZ.Logger.LogError("Error saving dataset: " + e.Message); return SzResult.Failure(e.Message); } } public async Task> LoadDatasetAsync(string datasetId, CancellationToken ct = default) { if (_loadedDatasets.TryGetValue(datasetId, out SzDataset? value)) return SzResult.Success(value); var datasetPath = Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId, "dataset.json"); var json = await SZ.LocalFileManager.LoadFileAsync(datasetPath, ct); if (json is null) return SzResult.Failure($"Could not find dataset file for ID '{datasetId}'"); var parsedDataset = SZ.Parser.DeserializeDataset(json); if (parsedDataset is null) return SzResult.Failure($"Failed to parse dataset JSON for ID '{datasetId}'"); _loadedDatasets.TryAdd(parsedDataset.Id, parsedDataset); return SzResult.Success(parsedDataset); } public async Task> DeleteDatasetAsync(string datasetId) { return await Task.Run(() => { try { var path = Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId); if (Directory.Exists(path)) Directory.Delete(path, true); _loadedDatasets.Remove(datasetId); return SzResult.Success(true); } catch (Exception e) { return SzResult.Failure(e.Message); } }); } public async Task> CreateDatasetAsync(string name, string templateId, string version = "1_0", string? id = null) { if (string.IsNullOrEmpty(name)) return SzResult.Failure("Name empty."); var templateResult = await LoadTemplateAsync(templateId); if (!templateResult.IsSuccess || templateResult.Value is null) return SzResult.Failure($"Template '{templateId}' not found."); var newDataset = new SzDataset() { Name = name, Id = id ?? name.ToLower().Replace(" ", "-").Trim() + "@" + version, DataObjectTemplateId = templateResult.Value.Id, DataObjectType = templateResult.Value.DataObjectType, }; return SzResult.Success(newDataset); } public async Task> GetFieldValueFromPath(string path) { var parts = path.Split('.'); if (parts.Length < 3) return SzResult.Failure("Not enough arguments in path"); var datasetId = parts[0]; var dataObjectId = parts[1]; var fieldPath = string.Join(".", parts.Skip(2)); if (!datasetId.Contains('@')) { SZ.Logger.LogWarning($"Trying to get a field value from dataset `{datasetId}` but no dataset version was specified. Attempting to fallback to version 1.0"); datasetId += "@1_0"; } var datasetResult = await LoadDatasetAsync(datasetId); if (!datasetResult.IsSuccess) return SzResult.Failure($"Could not get field value, dataset with id '{datasetId}' could not be loaded: {datasetResult.Error}"); var dataset = datasetResult.Value; if (dataset is null) return SzResult.Failure("Dataset was null somehow"); if (!dataset.DataObjects.TryGetValue(dataObjectId, out var dataObject)) return SzResult.Failure($"Data object {dataObjectId} does not exist in dataset {datasetId}"); if (!dataObject.Fields.TryGetValue(fieldPath, out var field)) return SzResult.Failure($"Field {fieldPath} does not exist in Data Object {dataObjectId}"); return SzResult.Success(field.Value); } #endregion #region Templates public async Task> SaveTemplateAsync(ISzTemplate template, CancellationToken ct = default) { var templatePath = Path.Combine(SZ.LocalFileManager.TemplatesPath, template.Id, "template.json"); try { var json = SZ.Parser.SerializeTemplateToJson(template); var success = await SZ.LocalFileManager.SaveFileAsync(templatePath, json, ct); return success ? SzResult.Success(true) : SzResult.Failure("Failed to write template file."); } catch (Exception e) { return SzResult.Failure(e.Message); } } public async Task> LoadTemplateAsync(string templateId, CancellationToken ct = default) where T : ISzTemplate { if (_loadedTemplates.TryGetValue(templateId, out ISzTemplate? cachedTemplate)) return SzResult.Success((T)cachedTemplate); var path = Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId, "template.json"); var json = await SZ.LocalFileManager.LoadFileAsync(path, ct); if (json is null) return SzResult.Failure($"Template '{templateId}' not found."); var parsed = SZ.Parser.DeserializeTemplate(json); if (parsed is null) return SzResult.Failure("Parse error."); _loadedTemplates.TryAdd(parsed.Id, parsed); return SzResult.Success(parsed); } public async Task> DeleteTemplateAsync(string templateId) { return await Task.Run(() => { try { var path = Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId); if (Directory.Exists(path)) Directory.Delete(path, true); _loadedTemplates.Remove(templateId); return SzResult.Success(true); } catch (Exception e) { return SzResult.Failure(e.Message); } }); } #endregion #region Synchronous Creation Logic public SzResult CreateTemplateField(string id, SzFieldType fieldType, bool isList = false, string? defaultValue = null, bool isSpecialType = false, string? specialTypeValue = null) { if (string.IsNullOrEmpty(id)) return SzResult.Failure("ID cannot be empty."); return SzResult.Success(new SzTemplateField() { Id = id, FieldType = fieldType, IsList = isList, IsSpecialType = isSpecialType, DefaultValue = defaultValue ?? "", SpecialTypeValue = specialTypeValue ?? "" }); } public SzResult CreateDataObjectTemplate(string name, string dataObjectType, string version = "1_0", string? id = null, string? description = null, List? fields = null) { var newTemplate = new SzDataObjectTemplate() { Name = name, Id = id ?? name.ToLower().Replace(" ", "-").Trim() + "@" + version, DataObjectType = dataObjectType, Description = description ?? "" }; if (fields != null) { foreach (var field in fields) newTemplate.TemplateFields.TryAdd(field.Id, field); } return SzResult.Success(newTemplate); } public SzResult CreateDataObject(SzDataObjectTemplate template, string name, string? id = null) { var dataObject = new SzDataObject() { Name = name, Id = id ?? name.ToLower().Replace(" ", "-").Trim() }; var fieldsResult = CreateFieldsFromTemplate(template); if (!fieldsResult.IsSuccess) return SzResult.Failure(fieldsResult.Error!); dataObject.Fields = fieldsResult.Value!; return SzResult.Success(dataObject); } public SzResult> CreateFieldsFromTemplate(ISzTemplate template) { var fields = new Dictionary(); foreach (var tempField in template.TemplateFields.Values) { fields.Add(tempField.Id, new SzField { Id = tempField.Id, FieldType = tempField.FieldType, IsList = tempField.IsList }); } return SzResult>.Success(fields); } #endregion #region Bulk Operations public async Task LoadAllDatasetsAsync(CancellationToken ct = default) { _loadedDatasets.Clear(); if (!Directory.Exists(SZ.LocalFileManager.DatasetsPath)) return; var dirs = Directory.GetDirectories(SZ.LocalFileManager.DatasetsPath); foreach (var dir in dirs) { var id = Path.GetFileName(dir); await LoadDatasetAsync(id, ct); } } #endregion }