using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using MaksIT.UScheduler.ScheduleManager.Models;
namespace MaksIT.UScheduler.ScheduleManager.Services;
///
/// Service for loading and saving scriptsettings.json files.
///
public class ScriptSettingsService
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
///
/// Scans a directory for scriptsettings.json files and loads their schedule configurations.
///
public List LoadScriptsFromDirectory(string examplesPath)
{
var schedules = new List();
if (!Directory.Exists(examplesPath))
return schedules;
var settingsFiles = Directory.GetFiles(examplesPath, "scriptsettings.json", SearchOption.AllDirectories);
foreach (var filePath in settingsFiles)
{
try
{
var schedule = LoadScheduleFromFile(filePath);
if (schedule != null)
schedules.Add(schedule);
}
catch
{
// Skip files that can't be parsed
}
}
return schedules;
}
///
/// Loads the schedule configuration from a single scriptsettings.json file.
///
public ScriptSchedule? LoadScheduleFromFile(string filePath)
{
if (!File.Exists(filePath))
return null;
var json = File.ReadAllText(filePath);
var doc = JsonNode.Parse(json);
if (doc == null)
return null;
var title = doc["title"]?.GetValue() ?? Path.GetDirectoryName(filePath) ?? "Unknown";
var name = doc["name"]?.GetValue();
// Use name from JSON, or title with " Script Settings" suffix stripped for listbox display
var displayName = !string.IsNullOrWhiteSpace(name)
? name
: StripScriptSettingsSuffix(title);
var schedule = new ScriptSchedule
{
FilePath = filePath,
Name = displayName,
Title = title
};
var scheduleNode = doc["schedule"];
if (scheduleNode != null)
{
schedule.RunMonth = GetStringArray(scheduleNode["runMonth"]);
schedule.RunWeekday = GetStringArray(scheduleNode["runWeekday"]);
schedule.RunTime = GetStringArray(scheduleNode["runTime"]);
schedule.MinIntervalMinutes = scheduleNode["minIntervalMinutes"]?.GetValue() ?? 10;
}
return schedule;
}
///
/// Saves only the schedule section back to the scriptsettings.json file,
/// preserving all other content.
///
public void SaveScheduleToFile(ScriptSchedule schedule)
{
if (!File.Exists(schedule.FilePath))
throw new FileNotFoundException("Script settings file not found.", schedule.FilePath);
var json = File.ReadAllText(schedule.FilePath);
var doc = JsonNode.Parse(json);
if (doc == null)
throw new InvalidOperationException("Failed to parse JSON file.");
// Update or create the schedule section
var scheduleNode = new JsonObject
{
["runMonth"] = new JsonArray(schedule.RunMonth.Select(m => JsonValue.Create(m)).ToArray()),
["runWeekday"] = new JsonArray(schedule.RunWeekday.Select(d => JsonValue.Create(d)).ToArray()),
["runTime"] = new JsonArray(schedule.RunTime.Select(t => JsonValue.Create(t)).ToArray()),
["minIntervalMinutes"] = schedule.MinIntervalMinutes
};
doc["schedule"] = scheduleNode;
// Write back with proper formatting
var options = new JsonWriterOptions { Indented = true };
using var stream = File.Create(schedule.FilePath);
using var writer = new Utf8JsonWriter(stream, options);
doc.WriteTo(writer);
}
/// Strips " Script Settings" (case-insensitive) from the end of a title for listbox display.
private static string StripScriptSettingsSuffix(string title)
{
const string suffix = " Script Settings";
if (title.Length > suffix.Length && title.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
return title[..^suffix.Length].TrimEnd();
return title;
}
private static List GetStringArray(JsonNode? node)
{
if (node is not JsonArray array)
return [];
return array
.Where(item => item != null)
.Select(item => item!.GetValue())
.ToList();
}
}