package parser import ( "reflect" "strconv" "strings" ) // evaluateAllConditions checks all conditional logic func (p *Parser) evaluateAllConditions(fieldTag *FieldTag, _ reflect.Value) bool { if fieldTag.Condition != nil && !p.evaluateCondition(fieldTag.Condition) { return false } if fieldTag.IfVariableSet != "" && !p.isVariableSet(fieldTag.IfVariableSet) { return false } if fieldTag.IfVariableNotSet != "" && p.isVariableSet(fieldTag.IfVariableNotSet) { return false } if fieldTag.IfFlag != "" && !p.flags[fieldTag.IfFlag] { return false } if fieldTag.IfFlagNotSet != "" && p.flags[fieldTag.IfFlagNotSet] { return false } if fieldTag.IfEquals != "" { parts := strings.Split(fieldTag.IfEquals, "=") if len(parts) == 2 && !p.evaluateEqualsCondition(parts[0], parts[1]) { return false } } if fieldTag.IfNotEquals != "" { parts := strings.Split(fieldTag.IfNotEquals, "=") if len(parts) == 2 && p.evaluateEqualsCondition(parts[0], parts[1]) { return false } } return true } // evaluateCondition evaluates conditions for conditional fields func (p *Parser) evaluateCondition(condition *FieldCondition) bool { if condition.Type == "simple" { return p.isVariableSet(condition.Variable) } cachedValue, exists := p.resolveVariable(condition.Variable) if !exists { return false } compareValue, err := p.convertValue(condition.Value, cachedValue) if err != nil { return false } return p.compareValues(cachedValue, compareValue, condition.Operator) } // isVariableSet checks if a variable exists and has a truthy value func (p *Parser) isVariableSet(variable string) bool { cachedValue, exists := p.resolveVariable(variable) if !exists { return false } return p.isTruthy(cachedValue) } // evaluateEqualsCondition checks field equality func (p *Parser) evaluateEqualsCondition(variable, value string) bool { cachedValue, exists := p.resolveVariable(variable) if !exists { return false } compareValue, err := p.convertValue(value, cachedValue) if err != nil { return false } return p.compareValues(cachedValue, compareValue, "==") } // evaluateType2Criteria evaluates type2 criteria for alternative types with string length support func (p *Parser) evaluateType2Criteria(criteria string) bool { // String length operators: !>, !<, !>=, !<=, != stringLengthOps := []string{"!>=", "!<=", "!>", "!<", "!="} for _, op := range stringLengthOps { if idx := strings.Index(criteria, op); idx > 0 { fieldName := strings.TrimSpace(criteria[:idx]) valueStr := strings.TrimSpace(criteria[idx+len(op):]) cachedValue, exists := p.resolveVariable(fieldName) if !exists { return false } return p.evaluateStringLengthCondition(cachedValue, valueStr, op) } } // Standard comparison operators operators := []string{">=", "<=", ">", "<", "=="} for _, op := range operators { if idx := strings.Index(criteria, op); idx > 0 { fieldName := strings.TrimSpace(criteria[:idx]) valueStr := strings.TrimSpace(criteria[idx+len(op):]) cachedValue, exists := p.resolveVariable(fieldName) if !exists { return false } compareValue, err := p.convertValue(valueStr, cachedValue) if err != nil { return false } return p.compareValues(cachedValue, compareValue, op) } } return false } // evaluateStringLengthCondition evaluates string length conditions func (p *Parser) evaluateStringLengthCondition(value any, lengthStr, operator string) bool { var stringVal string // Extract string value from various types switch v := value.(type) { case string: stringVal = v default: // Try to get string representation from struct fields if reflect.TypeOf(value).Kind() == reflect.Struct { val := reflect.ValueOf(value) if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String { stringVal = dataField.String() } else { return false } } else { return false } } targetLength, err := strconv.Atoi(lengthStr) if err != nil { return false } stringLength := len(stringVal) switch operator { case "!>": return stringLength > targetLength case "!<": return stringLength < targetLength case "!>=": return stringLength >= targetLength case "!<=": return stringLength <= targetLength case "!=": return stringLength != targetLength default: return false } } // resolveVariable resolves variables with support for array indices and complex patterns func (p *Parser) resolveVariable(variable string) (any, bool) { // Handle %i patterns by replacing with current array index if strings.Contains(variable, "%i") { currentIndex := p.GetCurrentArrayIndex() if currentIndex >= 0 { variable = strings.ReplaceAll(variable, "%i", strconv.Itoa(currentIndex)) } } // Check field cache first if cachedValue, exists := p.fieldCache[variable]; exists { return cachedValue, true } // Handle array index patterns like "header_info_mod_need_0" if strings.Contains(variable, "_") { if value, exists := p.resolveArrayIndexVariable(variable); exists { return value, true } } // Check current struct if p.currentStruct.IsValid() { if field := p.currentStruct.FieldByName(variable); field.IsValid() { return field.Interface(), true } } // Check struct stack for nested resolution for i := len(p.structStack) - 1; i >= 0; i-- { if field := p.structStack[i].FieldByName(variable); field.IsValid() { return field.Interface(), true } } return nil, false } // resolveArrayIndexVariable handles variables with array index suffixes func (p *Parser) resolveArrayIndexVariable(variable string) (any, bool) { parts := strings.Split(variable, "_") if len(parts) < 2 { return nil, false } // Try to extract index from last part lastPart := parts[len(parts)-1] if index, err := strconv.Atoi(lastPart); err == nil { // Reconstruct base variable name without index baseVar := strings.Join(parts[:len(parts)-1], "_") // Look for array/slice field with this base name if cachedValue, exists := p.fieldCache[baseVar]; exists { return p.getArrayElement(cachedValue, index) } // Check current struct for array field if p.currentStruct.IsValid() { if field := p.currentStruct.FieldByName(baseVar); field.IsValid() { return p.getArrayElement(field.Interface(), index) } } // Check struct stack for i := len(p.structStack) - 1; i >= 0; i-- { if field := p.structStack[i].FieldByName(baseVar); field.IsValid() { return p.getArrayElement(field.Interface(), index) } } } return nil, false } // getArrayElement safely extracts element from array/slice func (p *Parser) getArrayElement(value any, index int) (any, bool) { val := reflect.ValueOf(value) switch val.Kind() { case reflect.Slice, reflect.Array: if index >= 0 && index < val.Len() { return val.Index(index).Interface(), true } } return nil, false }