package classes import ( "fmt" "sync" ) // ClassManager provides high-level class management functionality type ClassManager struct { classes *Classes utils *ClassUtils integration *ClassIntegration // Statistics tracking classUsageStats map[int8]int32 // Track how often each class is used // Thread safety mutex sync.RWMutex } // NewClassManager creates a new class manager func NewClassManager() *ClassManager { return &ClassManager{ classes: GetGlobalClasses(), utils: NewClassUtils(), integration: NewClassIntegration(), classUsageStats: make(map[int8]int32), } } // RegisterClassUsage tracks class usage for statistics func (cm *ClassManager) RegisterClassUsage(classID int8) { if !cm.classes.IsValidClassID(classID) { return } cm.mutex.Lock() defer cm.mutex.Unlock() cm.classUsageStats[classID]++ } // GetClassUsageStats returns class usage statistics func (cm *ClassManager) GetClassUsageStats() map[int8]int32 { cm.mutex.RLock() defer cm.mutex.RUnlock() // Return a copy to prevent external modification stats := make(map[int8]int32) for classID, count := range cm.classUsageStats { stats[classID] = count } return stats } // GetMostPopularClass returns the most frequently used class func (cm *ClassManager) GetMostPopularClass() (int8, int32) { cm.mutex.RLock() defer cm.mutex.RUnlock() var mostPopularClass int8 = -1 var maxUsage int32 = 0 for classID, usage := range cm.classUsageStats { if usage > maxUsage { maxUsage = usage mostPopularClass = classID } } return mostPopularClass, maxUsage } // GetLeastPopularClass returns the least frequently used class func (cm *ClassManager) GetLeastPopularClass() (int8, int32) { cm.mutex.RLock() defer cm.mutex.RUnlock() var leastPopularClass int8 = -1 var minUsage int32 = -1 for classID, usage := range cm.classUsageStats { if minUsage == -1 || usage < minUsage { minUsage = usage leastPopularClass = classID } } return leastPopularClass, minUsage } // ResetUsageStats clears all usage statistics func (cm *ClassManager) ResetUsageStats() { cm.mutex.Lock() defer cm.mutex.Unlock() cm.classUsageStats = make(map[int8]int32) } // ProcessClassCommand handles class-related commands func (cm *ClassManager) ProcessClassCommand(command string, args []string) (string, error) { switch command { case "list": return cm.handleListCommand(args) case "info": return cm.handleInfoCommand(args) case "random": return cm.handleRandomCommand(args) case "stats": return cm.handleStatsCommand(args) case "search": return cm.handleSearchCommand(args) case "progression": return cm.handleProgressionCommand(args) default: return "", fmt.Errorf("unknown class command: %s", command) } } // handleListCommand lists classes by criteria func (cm *ClassManager) handleListCommand(args []string) (string, error) { if len(args) == 0 { // List all classes allClasses := cm.classes.GetAllClasses() result := "All Classes:\n" for classID, displayName := range allClasses { classType := cm.classes.GetClassType(classID) baseClass := cm.classes.GetBaseClass(classID) baseClassName := cm.classes.GetClassNameCase(baseClass) result += fmt.Sprintf("%d: %s (%s, Base: %s)\n", classID, displayName, classType, baseClassName) } return result, nil } // List classes by type classType := args[0] allClasses := cm.classes.GetAllClasses() result := fmt.Sprintf("%s Classes:\n", classType) count := 0 for classID, displayName := range allClasses { if cm.classes.GetClassType(classID) == classType { baseClass := cm.classes.GetBaseClass(classID) baseClassName := cm.classes.GetClassNameCase(baseClass) result += fmt.Sprintf("%d: %s (Base: %s)\n", classID, displayName, baseClassName) count++ } } if count == 0 { return fmt.Sprintf("No classes found for type: %s", classType), nil } return result, nil } // handleInfoCommand provides detailed information about a class func (cm *ClassManager) handleInfoCommand(args []string) (string, error) { if len(args) == 0 { return "", fmt.Errorf("class name or ID required") } // Try to parse as class name or ID classID := cm.utils.ParseClassName(args[0]) if classID == -1 { return fmt.Sprintf("Invalid class: %s", args[0]), nil } classInfo := cm.classes.GetClassInfo(classID) if !classInfo["valid"].(bool) { return fmt.Sprintf("Invalid class ID: %d", classID), nil } result := fmt.Sprintf("Class Information:\n") result += fmt.Sprintf("ID: %d\n", classID) result += fmt.Sprintf("Name: %s\n", classInfo["display_name"]) result += fmt.Sprintf("Type: %s\n", classInfo["type"]) result += fmt.Sprintf("Base Class: %s\n", cm.classes.GetClassNameCase(classInfo["base_class"].(int8))) if secondaryBase := classInfo["secondary_base_class"].(int8); secondaryBase != DefaultClassID { result += fmt.Sprintf("Secondary Base: %s\n", cm.classes.GetClassNameCase(secondaryBase)) } result += fmt.Sprintf("Description: %s\n", cm.utils.GetClassDescription(classID)) // Add progression path progression := cm.utils.GetClassProgression(classID) if len(progression) > 1 { result += "Progression Path: " progressionNames := make([]string, len(progression)) for i, progClassID := range progression { progressionNames[i] = cm.classes.GetClassNameCase(progClassID) } result += fmt.Sprintf("%s\n", cm.utils.FormatClassList(progression, " → ")) } // Add starting stats startingStats := cm.integration.GetClassStartingStats(classID) if len(startingStats) > 0 { result += "Starting Stats:\n" for stat, value := range startingStats { result += fmt.Sprintf(" %s: %d\n", stat, value) } } // Add usage statistics if available cm.mutex.RLock() usage, hasUsage := cm.classUsageStats[classID] cm.mutex.RUnlock() if hasUsage { result += fmt.Sprintf("Usage Count: %d\n", usage) } return result, nil } // handleRandomCommand generates random classes func (cm *ClassManager) handleRandomCommand(args []string) (string, error) { classType := ClassTypeAdventure if len(args) > 0 { classType = args[0] } classID := cm.utils.GetRandomClassByType(classType) if classID == -1 { return "Failed to generate random class", nil } displayName := cm.classes.GetClassNameCase(classID) actualType := cm.classes.GetClassType(classID) return fmt.Sprintf("Random %s Class: %s (ID: %d)", actualType, displayName, classID), nil } // handleStatsCommand shows class system statistics func (cm *ClassManager) handleStatsCommand(args []string) (string, error) { systemStats := cm.utils.GetClassStatistics() usageStats := cm.GetClassUsageStats() result := "Class System Statistics:\n" result += fmt.Sprintf("Total Classes: %d\n", systemStats["total_classes"]) result += fmt.Sprintf("Adventure Classes: %d\n", systemStats["adventure_classes"]) result += fmt.Sprintf("Tradeskill Classes: %d\n", systemStats["tradeskill_classes"]) result += fmt.Sprintf("Special Classes: %d\n", systemStats["special_classes"]) if len(usageStats) > 0 { result += "\nUsage Statistics:\n" mostPopular, maxUsage := cm.GetMostPopularClass() leastPopular, minUsage := cm.GetLeastPopularClass() if mostPopular != -1 { mostPopularName := cm.classes.GetClassNameCase(mostPopular) result += fmt.Sprintf("Most Popular: %s (%d uses)\n", mostPopularName, maxUsage) } if leastPopular != -1 { leastPopularName := cm.classes.GetClassNameCase(leastPopular) result += fmt.Sprintf("Least Popular: %s (%d uses)\n", leastPopularName, minUsage) } } // Show base class distribution if baseDistribution, exists := systemStats["base_class_distribution"]; exists { result += "\nBase Class Distribution:\n" distribution := baseDistribution.(map[string][]string) for baseClass, subClasses := range distribution { result += fmt.Sprintf("%s: %d subclasses\n", baseClass, len(subClasses)) } } return result, nil } // handleSearchCommand searches for classes by pattern func (cm *ClassManager) handleSearchCommand(args []string) (string, error) { if len(args) == 0 { return "", fmt.Errorf("search pattern required") } pattern := args[0] matchingClasses := cm.utils.GetClassesByPattern(pattern) if len(matchingClasses) == 0 { return fmt.Sprintf("No classes found matching pattern: %s", pattern), nil } result := fmt.Sprintf("Classes matching '%s':\n", pattern) for _, classID := range matchingClasses { displayName := cm.classes.GetClassNameCase(classID) classType := cm.classes.GetClassType(classID) baseClass := cm.classes.GetBaseClass(classID) baseClassName := cm.classes.GetClassNameCase(baseClass) result += fmt.Sprintf("%d: %s (%s, Base: %s)\n", classID, displayName, classType, baseClassName) } return result, nil } // handleProgressionCommand shows class progression information func (cm *ClassManager) handleProgressionCommand(args []string) (string, error) { if len(args) == 0 { return "", fmt.Errorf("class name or ID required") } classID := cm.utils.ParseClassName(args[0]) if classID == -1 { return fmt.Sprintf("Invalid class: %s", args[0]), nil } progression := cm.utils.GetClassProgression(classID) if len(progression) <= 1 { return fmt.Sprintf("Class %s has no progression path", cm.classes.GetClassNameCase(classID)), nil } result := fmt.Sprintf("Progression Path for %s:\n", cm.classes.GetClassNameCase(classID)) for i, stepClassID := range progression { stepName := cm.classes.GetClassNameCase(stepClassID) if i == 0 { result += fmt.Sprintf("1. %s (Starting Class)\n", stepName) } else if i == len(progression)-1 { result += fmt.Sprintf("%d. %s (Final Class)\n", i+1, stepName) } else { result += fmt.Sprintf("%d. %s\n", i+1, stepName) } } return result, nil } // ValidateEntityClasses validates classes for a collection of entities func (cm *ClassManager) ValidateEntityClasses(entities []ClassAware) map[string]interface{} { validationResults := make(map[string]interface{}) validCount := 0 invalidCount := 0 classDistribution := make(map[int8]int) for i, entity := range entities { classID := entity.GetClass() isValid := cm.classes.IsValidClassID(classID) if isValid { validCount++ classDistribution[classID]++ } else { invalidCount++ } // Track invalid entities if !isValid { if validationResults["invalid_entities"] == nil { validationResults["invalid_entities"] = make([]map[string]interface{}, 0) } invalidList := validationResults["invalid_entities"].([]map[string]interface{}) invalidList = append(invalidList, map[string]interface{}{ "index": i, "class_id": classID, }) validationResults["invalid_entities"] = invalidList } } validationResults["total_entities"] = len(entities) validationResults["valid_count"] = validCount validationResults["invalid_count"] = invalidCount validationResults["class_distribution"] = classDistribution return validationResults } // GetClassRecommendations returns class recommendations for character creation func (cm *ClassManager) GetClassRecommendations(preferences map[string]interface{}) []int8 { recommendations := make([]int8, 0) // Check for class type preference if classType, exists := preferences["class_type"]; exists { if typeStr, ok := classType.(string); ok { allClasses := cm.classes.GetAllClasses() for classID := range allClasses { if cm.classes.GetClassType(classID) == typeStr { recommendations = append(recommendations, classID) } } } } // Check for base class preference if baseClass, exists := preferences["base_class"]; exists { if baseClassID, ok := baseClass.(int8); ok { subClasses := cm.utils.GetClassesByBaseClass(baseClassID) recommendations = append(recommendations, subClasses...) } } // Check for specific stat preferences if preferredStats, exists := preferences["preferred_stats"]; exists { if stats, ok := preferredStats.([]string); ok { allClasses := cm.classes.GetAllClasses() for classID := range allClasses { startingStats := cm.integration.GetClassStartingStats(classID) // Check if this class has bonuses in preferred stats hasPreferredBonus := false for _, preferredStat := range stats { if statValue, exists := startingStats[preferredStat]; exists && statValue > 52 { // Above base of 50 + minor bonus hasPreferredBonus = true break } } if hasPreferredBonus { recommendations = append(recommendations, classID) } } } } // If no specific preferences, recommend popular classes if len(recommendations) == 0 { // Get usage stats and recommend most popular classes usageStats := cm.GetClassUsageStats() if len(usageStats) > 0 { // Sort by usage and take top classes // For simplicity, just return all classes with usage > 0 for classID, usage := range usageStats { if usage > 0 { recommendations = append(recommendations, classID) } } } // If still no recommendations, return a default set of beginner-friendly classes if len(recommendations) == 0 { recommendations = []int8{ClassWarrior, ClassCleric, ClassWizard, ClassRogue} } } return recommendations } // Global class manager instance var globalClassManager *ClassManager var initClassManagerOnce sync.Once // GetGlobalClassManager returns the global class manager (singleton) func GetGlobalClassManager() *ClassManager { initClassManagerOnce.Do(func() { globalClassManager = NewClassManager() }) return globalClassManager }