package common import ( "fmt" "strings" "sync" ) // Variable represents a configuration variable with name, value, and optional comment type Variable struct { name string value string comment string } // NewVariable creates a new variable func NewVariable(name, value, comment string) *Variable { return &Variable{ name: name, value: value, comment: comment, } } // GetName returns the variable name func (v *Variable) GetName() string { return v.name } // GetValue returns the variable value func (v *Variable) GetValue() string { return v.value } // GetComment returns the variable comment func (v *Variable) GetComment() string { return v.comment } // GetNameValuePair returns the name and value as a single string func (v *Variable) GetNameValuePair() string { return fmt.Sprintf("%s %s", v.name, v.value) } // SetValue updates the variable value func (v *Variable) SetValue(value string) { v.value = value } // Variables manages a collection of configuration variables type Variables struct { variables map[string]*Variable mutex sync.RWMutex } // NewVariables creates a new variables manager func NewVariables() *Variables { return &Variables{ variables: make(map[string]*Variable), } } // AddVariable adds a variable to the collection func (v *Variables) AddVariable(variable *Variable) { v.mutex.Lock() defer v.mutex.Unlock() v.variables[variable.name] = variable } // FindVariable finds a variable by exact name func (v *Variables) FindVariable(name string) *Variable { v.mutex.RLock() defer v.mutex.RUnlock() return v.variables[name] } // GetVariable is an alias for FindVariable for convenience func (v *Variables) GetVariable(name string) *Variable { return v.FindVariable(name) } // GetVariables returns all variables that contain the partial name func (v *Variables) GetVariables(partialName string) []*Variable { v.mutex.RLock() defer v.mutex.RUnlock() results := make([]*Variable, 0) partialLower := strings.ToLower(partialName) for name, variable := range v.variables { if strings.Contains(strings.ToLower(name), partialLower) { results = append(results, variable) } } return results } // GetAllVariables returns all variables in the collection func (v *Variables) GetAllVariables() map[string]*Variable { v.mutex.RLock() defer v.mutex.RUnlock() // Return a copy to prevent external modification result := make(map[string]*Variable) for name, variable := range v.variables { result[name] = variable } return result } // GetVariableNames returns all variable names func (v *Variables) GetVariableNames() []string { v.mutex.RLock() defer v.mutex.RUnlock() names := make([]string, 0, len(v.variables)) for name := range v.variables { names = append(names, name) } return names } // SetVariable sets or updates a variable value func (v *Variables) SetVariable(name, value string) { v.mutex.Lock() defer v.mutex.Unlock() if variable, exists := v.variables[name]; exists { variable.SetValue(value) } else { // Create new variable if it doesn't exist v.variables[name] = NewVariable(name, value, "") } } // DeleteVariable removes a variable by name func (v *Variables) DeleteVariable(name string) bool { v.mutex.Lock() defer v.mutex.Unlock() if _, exists := v.variables[name]; exists { delete(v.variables, name) return true } return false } // ClearVariables removes all variables func (v *Variables) ClearVariables() { v.mutex.Lock() defer v.mutex.Unlock() v.variables = make(map[string]*Variable) } // Count returns the number of variables func (v *Variables) Count() int { v.mutex.RLock() defer v.mutex.RUnlock() return len(v.variables) } // HasVariable checks if a variable exists func (v *Variables) HasVariable(name string) bool { v.mutex.RLock() defer v.mutex.RUnlock() _, exists := v.variables[name] return exists } // GetVariableValue returns just the value of a variable, or empty string if not found func (v *Variables) GetVariableValue(name string) string { if variable := v.FindVariable(name); variable != nil { return variable.GetValue() } return "" } // GetVariableValueWithDefault returns the value of a variable, or a default if not found func (v *Variables) GetVariableValueWithDefault(name, defaultValue string) string { if variable := v.FindVariable(name); variable != nil { return variable.GetValue() } return defaultValue } // GetVariableAsInt attempts to parse a variable value as an integer func (v *Variables) GetVariableAsInt(name string, defaultValue int) int { if variable := v.FindVariable(name); variable != nil { var intValue int if _, err := fmt.Sscanf(variable.GetValue(), "%d", &intValue); err == nil { return intValue } } return defaultValue } // GetVariableAsFloat attempts to parse a variable value as a float func (v *Variables) GetVariableAsFloat(name string, defaultValue float64) float64 { if variable := v.FindVariable(name); variable != nil { var floatValue float64 if _, err := fmt.Sscanf(variable.GetValue(), "%f", &floatValue); err == nil { return floatValue } } return defaultValue } // GetVariableAsBool attempts to parse a variable value as a boolean func (v *Variables) GetVariableAsBool(name string, defaultValue bool) bool { if variable := v.FindVariable(name); variable != nil { value := strings.ToLower(variable.GetValue()) switch value { case "true", "1", "yes", "on", "enabled": return true case "false", "0", "no", "off", "disabled": return false } } return defaultValue } // Clone creates a deep copy of the variables collection func (v *Variables) Clone() *Variables { v.mutex.RLock() defer v.mutex.RUnlock() newVars := NewVariables() for name, variable := range v.variables { newVar := NewVariable(variable.name, variable.value, variable.comment) newVars.variables[name] = newVar } return newVars } // Merge merges another Variables collection into this one // If overwrite is true, existing variables will be overwritten func (v *Variables) Merge(other *Variables, overwrite bool) { if other == nil { return } v.mutex.Lock() defer v.mutex.Unlock() otherVars := other.GetAllVariables() for name, variable := range otherVars { if _, exists := v.variables[name]; !exists || overwrite { v.variables[name] = NewVariable(variable.name, variable.value, variable.comment) } } }