using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Haoliang.Models.System;
namespace Haoliang.Core.Services
{
public interface IRulesService
{
///
/// Get all business rules
///
Task> GetAllRulesAsync();
///
/// Create or update business rule
///
Task CreateOrUpdateRuleAsync(BusinessRuleConfig rule);
///
/// Delete business rule
///
Task DeleteRuleAsync(int ruleId);
///
/// Get statistics rules
///
Task> GetStatisticsRulesAsync();
///
/// Update statistics rules
///
Task UpdateStatisticsRulesAsync(List rules);
///
/// Validate business rule expression
///
Task ValidateRuleAsync(BusinessRuleConfig rule);
///
/// Evaluate business rule against data
///
Task EvaluateRuleAsync(BusinessRuleConfig rule, object data);
///
/// Get rule execution history
///
Task> GetRuleExecutionHistoryAsync(int ruleId, DateTime? startDate = null, DateTime? endDate = null);
}
public class RulesService : IRulesService
{
private readonly ISystemRepository _systemRepository;
private readonly IProductionRepository _productionRepository;
private readonly IAlarmRepository _alarmRepository;
private readonly ICacheService _cacheService;
public RulesService(
ISystemRepository systemRepository,
IProductionRepository productionRepository,
IAlarmRepository alarmRepository,
ICacheService cacheService)
{
_systemRepository = systemRepository;
_productionRepository = productionRepository;
_alarmRepository = alarmRepository;
_cacheService = cacheService;
}
public async Task> GetAllRulesAsync()
{
return await _cacheService.GetOrSetAllRulesAsync(() =>
_systemRepository.GetAllBusinessRulesAsync());
}
public async Task CreateOrUpdateRuleAsync(BusinessRuleConfig rule)
{
// Validate rule before saving
var validationResult = await ValidateRuleAsync(rule);
if (!validationResult.IsValid)
{
throw new ArgumentException($"Invalid rule: {validationResult.ErrorMessage}");
}
// Save rule to repository
var savedRule = await _systemRepository.SaveBusinessRuleAsync(rule);
// Clear cache
_cacheService.InvalidateRulesCache();
return savedRule;
}
public async Task DeleteRuleAsync(int ruleId)
{
var result = await _systemRepository.DeleteBusinessRuleAsync(ruleId);
if (result)
{
_cacheService.InvalidateRulesCache();
}
return result;
}
public async Task> GetStatisticsRulesAsync()
{
return await _cacheService.GetOrSetAllStatisticsRulesAsync(() =>
_systemRepository.GetAllStatisticsRulesAsync());
}
public async Task UpdateStatisticsRulesAsync(List rules)
{
// Validate all rules
foreach (var rule in rules)
{
var validationResult = await ValidateStatisticsRuleAsync(rule);
if (!validationResult.IsValid)
{
throw new ArgumentException($"Invalid statistics rule: {validationResult.ErrorMessage}");
}
}
// Save all rules
var result = await _systemRepository.SaveStatisticsRulesAsync(rules);
if (result)
{
_cacheService.InvalidateRulesCache();
}
return result;
}
public async Task ValidateRuleAsync(BusinessRuleConfig rule)
{
var result = new RuleValidationResult { IsValid = true };
if (rule == null)
{
result.IsValid = false;
result.ErrorMessage = "Rule cannot be null";
return result;
}
if (string.IsNullOrWhiteSpace(rule.RuleName))
{
result.IsValid = false;
result.ErrorMessage = "Rule name cannot be empty";
return result;
}
if (string.IsNullOrWhiteSpace(rule.RuleExpression))
{
result.IsValid = false;
result.ErrorMessage = "Rule expression cannot be empty";
return result;
}
// Validate rule syntax
if (!IsValidRuleExpression(rule.RuleExpression))
{
result.IsValid = false;
result.ErrorMessage = "Invalid rule expression syntax";
return result;
}
// Test rule with sample data
try
{
var sampleData = GetSampleDataForRule(rule);
var testResult = await EvaluateRuleAsync(rule, sampleData);
if (!testResult.Success)
{
result.IsValid = false;
result.ErrorMessage = $"Rule evaluation failed: {testResult.ErrorMessage}";
}
}
catch (Exception ex)
{
result.IsValid = false;
result.ErrorMessage = $"Rule validation error: {ex.Message}";
}
return result;
}
public async Task EvaluateRuleAsync(BusinessRuleConfig rule, object data)
{
var result = new RuleEvaluationResult { Success = true };
try
{
// Parse and evaluate the rule expression
var evaluator = new RuleExpressionEvaluator();
var evaluationResult = evaluator.Evaluate(rule.RuleExpression, data);
result.Success = evaluationResult.Success;
result.Result = evaluationResult.Result;
result.EvaluationTime = evaluationResult.EvaluationTime;
result.ErrorMessage = evaluationResult.ErrorMessage;
// Log rule execution if successful
if (result.Success && rule.Enabled)
{
await LogRuleExecutionAsync(rule, data, result);
}
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = ex.Message;
}
return result;
}
public async Task> GetRuleExecutionHistoryAsync(int ruleId, DateTime? startDate = null, DateTime? endDate = null)
{
return await _systemRepository.GetRuleExecutionHistoryAsync(ruleId, startDate, endDate);
}
#region Private Methods
private bool IsValidRuleExpression(string expression)
{
// Basic validation - in a real implementation, you would use a proper expression parser
return !string.IsNullOrWhiteSpace(expression) &&
!expression.Contains("DELETE") &&
!expression.Contains("DROP") &&
!expression.Contains("TRUNCATE");
}
private object GetSampleDataForRule(BusinessRuleConfig rule)
{
// Return sample data based on rule type
return new
{
Production = new { Quantity = 100, Target = 120, Quality = 95 },
Device = new { Status = "Running", Efficiency = 85 },
Time = DateTime.Now
};
}
private async Task ValidateStatisticsRuleAsync(StatisticsRuleConfig rule)
{
// Implementation for validating statistics rules
if (string.IsNullOrWhiteSpace(rule.RuleName))
{
throw new ArgumentException("Statistics rule name cannot be empty");
}
if (string.IsNullOrWhiteSpace(rule.CalculationExpression))
{
throw new ArgumentException("Statistics rule calculation expression cannot be empty");
}
}
private async Task LogRuleExecutionAsync(BusinessRuleConfig rule, object data, RuleEvaluationResult result)
{
var execution = new RuleExecutionHistory
{
RuleId = rule.RuleId,
RuleName = rule.RuleName,
InputDataJson = System.Text.Json.JsonSerializer.Serialize(data),
Result = result.Result?.ToString(),
Success = result.Success,
ErrorMessage = result.ErrorMessage,
ExecutionTime = DateTime.UtcNow
};
await _systemRepository.LogRuleExecutionAsync(execution);
}
#endregion
}
#region Supporting Classes
public class RuleExpressionEvaluator
{
public RuleEvaluationResult Evaluate(string expression, object data)
{
var result = new RuleEvaluationResult();
var startTime = DateTime.UtcNow;
try
{
// Parse the expression and evaluate against data
// This is a simplified implementation
// In a real scenario, you would use a proper expression parser or scripting engine
var parser = new ExpressionParser();
var evaluationResult = parser.ParseAndEvaluate(expression, data);
result.Success = evaluationResult.Success;
result.Result = evaluationResult.Value;
result.ErrorMessage = evaluationResult.Error;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = ex.Message;
}
result.EvaluationTime = DateTime.UtcNow - startTime;
return result;
}
}
public class ExpressionParser
{
public ParseResult ParseAndEvaluate(string expression, object data)
{
var result = new ParseResult();
try
{
// Simple expression evaluation
// In a real implementation, you would use a proper expression parser
// like NCalc, System.Linq.Dynamic.Core, or a custom parser
if (expression.Contains(">"))
{
var parts = expression.Split('>');
if (parts.Length == 2)
{
var left = EvaluateExpression(parts[0].Trim(), data);
var right = EvaluateExpression(parts[1].Trim(), data);
if (left != null && right != null)
{
result.Value = Convert.ToDecimal(left) > Convert.ToDecimal(right);
}
}
}
else if (expression.Contains("<"))
{
var parts = expression.Split('<');
if (parts.Length == 2)
{
var left = EvaluateExpression(parts[0].Trim(), data);
var right = EvaluateExpression(parts[1].Trim(), data);
if (left != null && right != null)
{
result.Value = Convert.ToDecimal(left) < Convert.ToDecimal(right);
}
}
}
else if (expression.Contains("="))
{
var parts = expression.Split('=');
if (parts.Length == 2)
{
var left = EvaluateExpression(parts[0].Trim(), data);
var right = EvaluateExpression(parts[1].Trim(), data);
if (left != null && right != null)
{
result.Value = left.ToString() == right.ToString();
}
}
}
else
{
// Simple value evaluation
result.Value = EvaluateExpression(expression, data);
}
result.Success = true;
}
catch (Exception ex)
{
result.Success = false;
result.Error = ex.Message;
}
return result;
}
private object EvaluateExpression(string expression, object data)
{
// Simple property extraction from data object
// In a real implementation, this would be more sophisticated
if (data is null)
return null;
// Handle simple property access
if (expression.Contains("."))
{
var parts = expression.Split('.');
if (parts.Length == 2)
{
var property = parts[1];
var dataDict = System.Text.Json.JsonSerializer.Deserialize>(
System.Text.Json.JsonSerializer.Serialize(data));
return dataDict?.TryGetValue(property, out var value) == true ? value : null;
}
}
// Handle simple numeric comparison
if (decimal.TryParse(expression, out var numericValue))
{
return numericValue;
}
return null;
}
}
public class ParseResult
{
public bool Success { get; set; }
public object Value { get; set; }
public string Error { get; set; }
}
public class RuleEvaluationResult
{
public bool Success { get; set; }
public object Result { get; set; }
public TimeSpan EvaluationTime { get; set; }
public string ErrorMessage { get; set; }
}
public class RuleValidationResult
{
public bool IsValid { get; set; }
public string ErrorMessage { get; set; }
public List Warnings { get; set; } = new List();
}
#endregion
}