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;
}
}
}
}