eq2go/internal/recipes/manager.go

153 lines
4.4 KiB
Go

package recipes
import (
"fmt"
"sync"
)
// RecipeManager provides high-level recipe system management with database integration
type RecipeManager struct {
db interface{} // Placeholder for database connection
masterRecipeList *MasterRecipeList
masterRecipeBookList *MasterRecipeBookList
loadedRecipes map[int32]*Recipe
loadedRecipeBooks map[int32]*Recipe
// Statistics
stats RecipeManagerStats
statisticsEnabled bool
// Thread safety
mu sync.RWMutex
}
// RecipeManagerStats contains statistics about recipe system operations
type RecipeManagerStats struct {
TotalRecipesLoaded int32 `json:"total_recipes_loaded"`
TotalRecipeBooksLoaded int32 `json:"total_recipe_books_loaded"`
LoadOperations int32 `json:"load_operations"`
SaveOperations int32 `json:"save_operations"`
ValidationErrors int32 `json:"validation_errors"`
mu sync.RWMutex
}
// NewRecipeManager creates a new recipe manager with database integration
func NewRecipeManager() *RecipeManager {
return &RecipeManager{
db: nil,
masterRecipeList: NewMasterRecipeList(),
masterRecipeBookList: NewMasterRecipeBookList(),
loadedRecipes: make(map[int32]*Recipe),
loadedRecipeBooks: make(map[int32]*Recipe),
statisticsEnabled: true,
}
}
// containsComponent checks if a component ID exists in a slice
func (rm *RecipeManager) containsComponent(components []int32, componentID int32) bool {
for _, comp := range components {
if comp == componentID {
return true
}
}
return false
}
// GetMasterRecipeList returns the master recipe list
func (rm *RecipeManager) GetMasterRecipeList() *MasterRecipeList {
return rm.masterRecipeList
}
// GetMasterRecipeBookList returns the master recipe book list
func (rm *RecipeManager) GetMasterRecipeBookList() *MasterRecipeBookList {
return rm.masterRecipeBookList
}
// GetRecipe returns a recipe by ID
func (rm *RecipeManager) GetRecipe(recipeID int32) *Recipe {
rm.mu.RLock()
defer rm.mu.RUnlock()
return rm.loadedRecipes[recipeID]
}
// GetRecipeBook returns a recipe book by ID
func (rm *RecipeManager) GetRecipeBook(bookID int32) *Recipe {
rm.mu.RLock()
defer rm.mu.RUnlock()
return rm.loadedRecipeBooks[bookID]
}
// GetStatistics returns current recipe system statistics
func (rm *RecipeManager) GetStatistics() RecipeManagerStats {
if !rm.statisticsEnabled {
return RecipeManagerStats{}
}
rm.stats.mu.RLock()
defer rm.stats.mu.RUnlock()
// Return a copy without the mutex to avoid copying lock value
return RecipeManagerStats{
TotalRecipesLoaded: rm.stats.TotalRecipesLoaded,
TotalRecipeBooksLoaded: rm.stats.TotalRecipeBooksLoaded,
LoadOperations: rm.stats.LoadOperations,
SaveOperations: rm.stats.SaveOperations,
ValidationErrors: rm.stats.ValidationErrors,
// Note: deliberately omitting mu field to avoid copying lock
}
}
// SetStatisticsEnabled enables or disables statistics collection
func (rm *RecipeManager) SetStatisticsEnabled(enabled bool) {
rm.mu.Lock()
defer rm.mu.Unlock()
rm.statisticsEnabled = enabled
}
// Validate performs comprehensive recipe system validation
func (rm *RecipeManager) Validate() []string {
rm.mu.RLock()
defer rm.mu.RUnlock()
var issues []string
// Validate master recipe list
if rm.masterRecipeList == nil {
issues = append(issues, "master recipe list is nil")
return issues
}
// Validate master recipe book list
if rm.masterRecipeBookList == nil {
issues = append(issues, "master recipe book list is nil")
}
// Check for recipes with invalid data
for _, recipe := range rm.loadedRecipes {
if recipe.ID == 0 {
issues = append(issues, fmt.Sprintf("recipe has invalid ID: %s", recipe.Name))
}
if recipe.Name == "" {
issues = append(issues, fmt.Sprintf("recipe %d has empty name", recipe.ID))
}
if recipe.Level < 0 || recipe.Level > 100 {
issues = append(issues, fmt.Sprintf("recipe %d has invalid level: %d", recipe.ID, recipe.Level))
}
if len(recipe.Products) != 5 {
issues = append(issues, fmt.Sprintf("recipe %d has invalid products array length: %d", recipe.ID, len(recipe.Products)))
}
}
return issues
}
// Size returns the total number of loaded recipes and recipe books
func (rm *RecipeManager) Size() (recipes int32, recipeBooks int32) {
rm.mu.RLock()
defer rm.mu.RUnlock()
return int32(len(rm.loadedRecipes)), int32(len(rm.loadedRecipeBooks))
}