package items import ( "dk/internal/store" "fmt" "sort" "sync" ) // Item represents an item in the game type Item struct { ID int `json:"id"` Type int `json:"type"` Name string `json:"name"` Value int `json:"value"` Att int `json:"att"` Special string `json:"special"` } func (i *Item) Save() error { itemStore := GetStore() itemStore.UpdateItem(i) return nil } func (i *Item) Delete() error { itemStore := GetStore() itemStore.RemoveItem(i.ID) return nil } // Creates a new Item with sensible defaults func New() *Item { return &Item{ Type: TypeWeapon, // Default to weapon Name: "", Value: 0, Att: 0, Special: "", } } // Validate checks if item has valid values func (i *Item) Validate() error { if i.Name == "" { return fmt.Errorf("item name cannot be empty") } if i.Type < TypeWeapon || i.Type > TypeShield { return fmt.Errorf("invalid item type: %d", i.Type) } if i.Value < 0 { return fmt.Errorf("item Value cannot be negative") } if i.Att < 0 { return fmt.Errorf("item Att cannot be negative") } return nil } // ItemType constants for item types const ( TypeWeapon = 1 TypeArmor = 2 TypeShield = 3 ) // ItemStore provides in-memory storage with O(1) lookups and item-specific indices type ItemStore struct { *store.BaseStore[Item] // Embedded generic store byType map[int][]int // Type -> []ID allByID []int // All IDs sorted by ID mu sync.RWMutex // Protects indices } // Global in-memory store var itemStore *ItemStore var storeOnce sync.Once // Initialize the in-memory store func initStore() { itemStore = &ItemStore{ BaseStore: store.NewBaseStore[Item](), byType: make(map[int][]int), allByID: make([]int, 0), } } // GetStore returns the global item store func GetStore() *ItemStore { storeOnce.Do(initStore) return itemStore } // AddItem adds an item to the in-memory store and updates all indices func (is *ItemStore) AddItem(item *Item) { is.mu.Lock() defer is.mu.Unlock() // Validate item if err := item.Validate(); err != nil { return } // Add to base store is.Add(item.ID, item) // Rebuild indices is.rebuildIndicesUnsafe() } // RemoveItem removes an item from the store and updates indices func (is *ItemStore) RemoveItem(id int) { is.mu.Lock() defer is.mu.Unlock() // Remove from base store is.Remove(id) // Rebuild indices is.rebuildIndicesUnsafe() } // UpdateItem updates an item efficiently func (is *ItemStore) UpdateItem(item *Item) { is.mu.Lock() defer is.mu.Unlock() // Validate item if err := item.Validate(); err != nil { return } // Update base store is.Add(item.ID, item) // Rebuild indices is.rebuildIndicesUnsafe() } // LoadData loads item data from JSON file, or starts with empty store func LoadData(dataPath string) error { is := GetStore() // Load from base store, which handles JSON loading if err := is.BaseStore.LoadData(dataPath); err != nil { return err } // Rebuild indices from loaded data is.rebuildIndices() return nil } // SaveData saves item data to JSON file func SaveData(dataPath string) error { is := GetStore() return is.BaseStore.SaveData(dataPath) } // rebuildIndicesUnsafe rebuilds all indices from base store data (caller must hold lock) func (is *ItemStore) rebuildIndicesUnsafe() { // Clear indices is.byType = make(map[int][]int) is.allByID = make([]int, 0) // Collect all items and build indices allItems := is.GetAll() for id, item := range allItems { // Type index is.byType[item.Type] = append(is.byType[item.Type], id) // All IDs is.allByID = append(is.allByID, id) } // Sort allByID by ID sort.Ints(is.allByID) // Sort type indices by ID for itemType := range is.byType { sort.Ints(is.byType[itemType]) } } // rebuildIndices rebuilds all item-specific indices from base store data func (is *ItemStore) rebuildIndices() { is.mu.Lock() defer is.mu.Unlock() is.rebuildIndicesUnsafe() } // Retrieves an item by ID func Find(id int) (*Item, error) { is := GetStore() item, exists := is.GetByID(id) if !exists { return nil, fmt.Errorf("item with ID %d not found", id) } return item, nil } // Retrieves all items func All() ([]*Item, error) { is := GetStore() is.mu.RLock() defer is.mu.RUnlock() result := make([]*Item, 0, len(is.allByID)) for _, id := range is.allByID { if item, exists := is.GetByID(id); exists { result = append(result, item) } } return result, nil } // Retrieves items by type func ByType(itemType int) ([]*Item, error) { is := GetStore() is.mu.RLock() defer is.mu.RUnlock() ids, exists := is.byType[itemType] if !exists { return []*Item{}, nil } result := make([]*Item, 0, len(ids)) for _, id := range ids { if item, exists := is.GetByID(id); exists { result = append(result, item) } } return result, nil } // Saves a new item to the in-memory store and sets the ID func (i *Item) Insert() error { is := GetStore() // Validate before insertion if err := i.Validate(); err != nil { return fmt.Errorf("validation failed: %w", err) } // Assign new ID if not set if i.ID == 0 { i.ID = is.GetNextID() } // Add to store is.AddItem(i) return nil } // Returns true if the item is a weapon func (i *Item) IsWeapon() bool { return i.Type == TypeWeapon } // Returns true if the item is armor func (i *Item) IsArmor() bool { return i.Type == TypeArmor } // Returns true if the item is a shield func (i *Item) IsShield() bool { return i.Type == TypeShield } // Returns the string representation of the item type func (i *Item) TypeName() string { switch i.Type { case TypeWeapon: return "Weapon" case TypeArmor: return "Armor" case TypeShield: return "Shield" default: return "Unknown" } } // Returns true if the item has special properties func (i *Item) HasSpecial() bool { return i.Special != "" } // Returns true if the item can be equipped func (i *Item) IsEquippable() bool { return i.Type == TypeWeapon || i.Type == TypeArmor || i.Type == TypeShield }