#if NET40_OR_GREATER || NETCOREAPP using System.Collections.Concurrent; #endif using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; using Newtonsoft.Json; using SabreTools.DatItems; namespace SabreTools.DatFiles { /// /// Item dictionary with statistics, bucketing, and sorting /// [JsonObject("items"), XmlRoot("items")] public class ItemDictionaryDB { #region Private instance variables /// /// Internal dictionary for all items /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP private readonly ConcurrentDictionary _items = new ConcurrentDictionary(); #else private readonly Dictionary _items = []; #endif /// /// Current highest available item index /// private long _itemIndex = 0; /// /// Internal dictionary for all machines /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP private readonly ConcurrentDictionary _machines = new ConcurrentDictionary(); #else private readonly Dictionary _machines = []; #endif /// /// Current highest available machine index /// private long _machineIndex = 0; /// /// Internal dictionary for item to machine mappings /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP private readonly ConcurrentDictionary _itemToMachineMapping = new ConcurrentDictionary(); #else private readonly Dictionary _itemToMachineMapping = []; #endif // TODO: Add another dictionary of string => ConcurrentList representing a bucketed key to a set of item IDs #endregion #region Fields /// /// DAT statistics /// [JsonIgnore, XmlIgnore] public DatStatistics DatStatistics { get; } = new DatStatistics(); #endregion #region Accessors /// /// Add an item, returning the insert index /// public long AddItem(DatItem item) { _items[_itemIndex++] = item; DatStatistics.AddItemStatistics(item); return _itemIndex - 1; } /// /// Add a machine, returning the insert index /// public long AddMachine(Machine machine) { _machines[_machineIndex++] = machine; return _machineIndex - 1; } /// /// Get an item based on the index /// public DatItem? GetItemByIndex(long index) { if (!_items.ContainsKey(index)) return null; return _items[index]; } /// /// Get a machine based on the index /// public Machine? GetMachineByIndex(long index) { if (!_machines.ContainsKey(index)) return null; return _machines[index]; } /// /// Get the machine associated with an item index /// public Machine? GetMachineForItemByIndex(long itemIndex) { if (!_itemToMachineMapping.ContainsKey(itemIndex)) return null; long machineIndex = _itemToMachineMapping[itemIndex]; if (!_machines.ContainsKey(machineIndex)) return null; return _machines[machineIndex]; } /// /// Get the items associated with a machine index /// public DatItem[]? GetDatItemsForMachineByIndex(long machineIndex) { var itemIds = _itemToMachineMapping .Where(mapping => mapping.Value == machineIndex) .Select(mapping => mapping.Key); var datItems = new List(); foreach (long itemId in itemIds) { if (_items.ContainsKey(itemId)) datItems.Add(_items[itemId]); } return datItems.ToArray(); } /// /// Remove an item, returning if it could be removed /// public bool RemoveItem(long itemIndex) { if (!_items.ContainsKey(itemIndex)) return false; #if NET40_OR_GREATER || NETCOREAPP _items.TryRemove(itemIndex, out _); #else _items.Remove(itemIndex); #endif if (_itemToMachineMapping.ContainsKey(itemIndex)) #if NET40_OR_GREATER || NETCOREAPP _itemToMachineMapping.TryRemove(itemIndex, out _); #else _itemToMachineMapping.Remove(itemIndex); #endif return true; } /// /// Remove a machine, returning if it could be removed /// public bool RemoveMachine(long machineIndex) { if (!_machines.ContainsKey(machineIndex)) return false; #if NET40_OR_GREATER || NETCOREAPP _machines.TryRemove(machineIndex, out _); #else _machines.Remove(machineIndex); #endif var itemIds = _itemToMachineMapping .Where(mapping => mapping.Value == machineIndex) .Select(mapping => mapping.Key); foreach (long itemId in itemIds) { #if NET40_OR_GREATER || NETCOREAPP _itemToMachineMapping.TryRemove(itemId, out _); #else _itemToMachineMapping.Remove(itemId); #endif } return true; } #endregion } }