using System; using System.Collections.Generic; using System.IO; using Microsoft.Data.Sqlite; namespace BoxPacker3D { /// /// Persistent template of an item that can be re-used across packing sessions. /// Stored in an on-disk SQLite database. /// public class ItemTemplate { public int Id { get; set; } public string Name { get; set; } = ""; public double Width { get; set; } public double Height { get; set; } public double Depth { get; set; } public override string ToString() => $"{Name} ({Width}×{Height}×{Depth} mm)"; } /// /// Simple SQLite-backed repository for s. /// Database schema is created on first use. /// public class ItemDatabase { private readonly string _connectionString; public ItemDatabase(string dbPath) { // Ensure directory exists var dir = Path.GetDirectoryName(dbPath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir); _connectionString = new SqliteConnectionStringBuilder { DataSource = dbPath, Mode = SqliteOpenMode.ReadWriteCreate }.ToString(); EnsureSchema(); } private void EnsureSchema() { using var conn = Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = @" CREATE TABLE IF NOT EXISTS items ( Id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL UNIQUE COLLATE NOCASE, Width REAL NOT NULL, Height REAL NOT NULL, Depth REAL NOT NULL );"; cmd.ExecuteNonQuery(); } private SqliteConnection Open() { var conn = new SqliteConnection(_connectionString); conn.Open(); return conn; } /// Returns all templates ordered alphabetically by name. public List GetAll() { var list = new List(); using var conn = Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items ORDER BY Name COLLATE NOCASE;"; using var rdr = cmd.ExecuteReader(); while (rdr.Read()) list.Add(new ItemTemplate { Id = rdr.GetInt32(0), Name = rdr.GetString(1), Width = rdr.GetDouble(2), Height = rdr.GetDouble(3), Depth = rdr.GetDouble(4) }); return list; } /// Returns the template with the given name or null if none exists. public ItemTemplate? FindByName(string name) { using var conn = Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items WHERE Name = $n COLLATE NOCASE LIMIT 1;"; cmd.Parameters.AddWithValue("$n", name); using var rdr = cmd.ExecuteReader(); if (rdr.Read()) return new ItemTemplate { Id = rdr.GetInt32(0), Name = rdr.GetString(1), Width = rdr.GetDouble(2), Height = rdr.GetDouble(3), Depth = rdr.GetDouble(4) }; return null; } /// Inserts or replaces a template (upsert by Name). public void Upsert(ItemTemplate item) { using var conn = Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = @" INSERT INTO items (Name, Width, Height, Depth) VALUES ($n, $w, $h, $d) ON CONFLICT(Name) DO UPDATE SET Width = excluded.Width, Height = excluded.Height, Depth = excluded.Depth;"; cmd.Parameters.AddWithValue("$n", item.Name); cmd.Parameters.AddWithValue("$w", item.Width); cmd.Parameters.AddWithValue("$h", item.Height); cmd.Parameters.AddWithValue("$d", item.Depth); cmd.ExecuteNonQuery(); } public void DeleteByName(string name) { using var conn = Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = "DELETE FROM items WHERE Name = $n COLLATE NOCASE;"; cmd.Parameters.AddWithValue("$n", name); cmd.ExecuteNonQuery(); } /// /// Checks if a template with the same name or exact dimensions already exists. /// Returns the existing template if found, null otherwise. /// public ItemTemplate? FindDuplicate(ItemTemplate item) { using var conn = Open(); using var cmd = conn.CreateCommand(); // Check for same name (case-insensitive) cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items WHERE Name = $n COLLATE NOCASE LIMIT 1;"; cmd.Parameters.AddWithValue("$n", item.Name); using (var rdr = cmd.ExecuteReader()) { if (rdr.Read()) { return new ItemTemplate { Id = rdr.GetInt32(0), Name = rdr.GetString(1), Width = rdr.GetDouble(2), Height = rdr.GetDouble(3), Depth = rdr.GetDouble(4) }; } } // Check for same dimensions (exact match) cmd.CommandText = @" SELECT Id, Name, Width, Height, Depth FROM items WHERE Width = $w AND Height = $h AND Depth = $d LIMIT 1;"; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("$w", item.Width); cmd.Parameters.AddWithValue("$h", item.Height); cmd.Parameters.AddWithValue("$d", item.Depth); using (var rdr = cmd.ExecuteReader()) { if (rdr.Read()) { return new ItemTemplate { Id = rdr.GetInt32(0), Name = rdr.GetString(1), Width = rdr.GetDouble(2), Height = rdr.GetDouble(3), Depth = rdr.GetDouble(4) }; } } return null; } } }