using System; using System.IO; using System.Text.Json; namespace BoxPacker3D { /// /// Strongly-typed representation of appsettings.json. /// Loaded once at startup via ; falls back to sensible defaults /// if the file is missing or malformed. /// public class AppSettings { public DatabaseSettings Database { get; set; } = new(); public DefaultBoxSettings DefaultBox { get; set; } = new(); public MaxBoxSettings MaxBox { get; set; } = new(); public PaddingSettings Padding { get; set; } = new(); public ViewSettings View { get; set; } = new(); public UISettings UI { get; set; } = new(); public class DatabaseSettings { public string FilePath { get; set; } = "items.db"; } public class DefaultBoxSettings { public double Width { get; set; } = 600; public double Height { get; set; } = 400; public double Depth { get; set; } = 500; public double WallThickness { get; set; } = 20; } public class MaxBoxSettings { public double Width { get; set; } = 1200; public double Height { get; set; } = 800; public double Depth { get; set; } = 1000; } public class PaddingSettings { public double WallPadding { get; set; } = 10; public double ItemPadding { get; set; } = 3; } public class ViewSettings { public int InitialRotationX { get; set; } = 30; public int InitialRotationY { get; set; } = 30; public int InitialZoomPercent { get; set; } = 100; } public class UISettings { public int WindowWidth { get; set; } = 1340; public int WindowHeight { get; set; } = 840; public int LeftPanelWidth { get; set; } = 500; } /// /// Loads appsettings.json from the application directory. /// If the file is missing or invalid, returns defaults and writes a warning to stderr. /// public static AppSettings Load() { string path = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); if (!File.Exists(path)) { Console.Error.WriteLine($"[AppSettings] {path} not found – using defaults."); return new AppSettings(); } try { var json = File.ReadAllText(path); var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; return JsonSerializer.Deserialize(json, opts) ?? new AppSettings(); } catch (Exception ex) { Console.Error.WriteLine($"[AppSettings] Failed to parse: {ex.Message} – using defaults."); return new AppSettings(); } } /// /// Resolves the writable database path. /// /// Priority: /// 1. If FilePath is absolute → use it as-is (developer override). /// 2. Otherwise → store in %AppData%\BoxPacker3D\<filename> so the /// file is always user-writable, even when the app is installed in /// Program Files (which is read-only for normal users). /// /// On first run the seed database is copied from the application directory /// to AppData so the user starts with the pre-built item catalogue. /// public string ResolvedDatabasePath { get { if (Path.IsPathRooted(Database.FilePath)) return Database.FilePath; // User-writable location: %AppData%\BoxPacker3D\items.db string appDataDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BoxPacker3D"); Directory.CreateDirectory(appDataDir); string userDbPath = Path.Combine(appDataDir, Path.GetFileName(Database.FilePath)); // Copy seed database on first run (do not overwrite user's existing data) if (!File.Exists(userDbPath)) { string seedPath = Path.Combine(AppContext.BaseDirectory, Database.FilePath); if (File.Exists(seedPath)) File.Copy(seedPath, userDbPath); } return userDbPath; } } } }