using ScadaLink.Commons.Entities.Templates; namespace ScadaLink.TemplateEngine; /// /// Enforces locking rules for template member overrides. /// /// Locking rules: /// - Locked members cannot be overridden downstream (child templates or compositions). /// - Any level can lock an unlocked member (intermediate locking). /// - Once locked, a member stays locked — it cannot be unlocked downstream. /// /// Override granularity: /// - Attributes: Value and Description overridable; DataType and DataSourceReference fixed. /// - Alarms: Priority, TriggerConfiguration, Description, OnTriggerScript overridable; Name and TriggerType fixed. /// - Scripts: Code, TriggerConfiguration, MinTimeBetweenRuns, params/return overridable; Name fixed. /// - Lock flag applies to the entire member (attribute/alarm/script). /// public static class LockEnforcer { /// /// Validates that an attribute override does not violate lock or granularity rules. /// public static string? ValidateAttributeOverride( TemplateAttribute original, TemplateAttribute proposed) { if (original.IsLocked) { return $"Attribute '{original.Name}' is locked and cannot be overridden."; } // DataType is fixed — cannot change if (proposed.DataType != original.DataType) { return $"Attribute '{original.Name}': DataType cannot be overridden (fixed)."; } // DataSourceReference is fixed — cannot change if (proposed.DataSourceReference != original.DataSourceReference) { return $"Attribute '{original.Name}': DataSourceReference cannot be overridden (fixed)."; } return null; } /// /// Validates that an alarm override does not violate lock or granularity rules. /// public static string? ValidateAlarmOverride( TemplateAlarm original, TemplateAlarm proposed) { if (original.IsLocked) { return $"Alarm '{original.Name}' is locked and cannot be overridden."; } // Name is fixed if (proposed.Name != original.Name) { return $"Alarm '{original.Name}': Name cannot be overridden (fixed)."; } // TriggerType is fixed if (proposed.TriggerType != original.TriggerType) { return $"Alarm '{original.Name}': TriggerType cannot be overridden (fixed)."; } return null; } /// /// Validates that a script override does not violate lock or granularity rules. /// public static string? ValidateScriptOverride( TemplateScript original, TemplateScript proposed) { if (original.IsLocked) { return $"Script '{original.Name}' is locked and cannot be overridden."; } // Name is fixed if (proposed.Name != original.Name) { return $"Script '{original.Name}': Name cannot be overridden (fixed)."; } return null; } /// /// Validates that a lock flag change is legal. /// Locking is allowed on unlocked members. Unlocking is never allowed. /// public static string? ValidateLockChange(bool originalIsLocked, bool proposedIsLocked, string memberName) { if (originalIsLocked && !proposedIsLocked) { return $"Member '{memberName}' is locked and cannot be unlocked."; } return null; } }