using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using TeamAAS.Communication.Config;
using TeamAAS.Communication.Models;
namespace TeamAAS.Communication
{
///
/// 全局变量管理器。懒汉单例:GlobalVariableManager.Instance。
/// 变量分两级作用域:Global(机器级固定,不随产品变) / Product(随产品变)。
/// 内存里是单一 列表(公式绑定层直接读它,零改动),
/// Scope 只决定持久化去向与编辑入口:
/// Global 子集存 Config\global_vars.json;Product 子集存 Products\<名>\global_vars.json。
///
public class GlobalVariableManager
{
#region 单例
private static readonly Lazy _instance =
new Lazy(() => new GlobalVariableManager(), isThreadSafe: true);
/// 懒汉单例入口。首次访问时初始化,线程安全。
public static GlobalVariableManager Instance => _instance.Value;
#endregion
private GlobalVariableManager()
{
Variables.CollectionChanged += (s, e) =>
{
if (e.NewItems != null)
foreach (GlobalVariableModel v in e.NewItems)
v.PropertyChanged += OnVariablePropertyChanged;
if (e.OldItems != null)
foreach (GlobalVariableModel v in e.OldItems)
v.PropertyChanged -= OnVariablePropertyChanged;
if (e.Action != System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
VariablesChanged?.Invoke();
};
}
private void OnVariablePropertyChanged(object sender, PropertyChangedEventArgs e)
{
VariablesChanged?.Invoke();
}
/// 全部全局变量(Global + 当前产品的 Product)。公式/结果注册表直接读它。
public ObservableCollection Variables { get; }
= new ObservableCollection();
public event Action VariablesChanged;
#region 变量 CRUD
/// 新建变量并加入 live 列表(默认 Product 作用域)。
public void AddVariable(string dataType, VarScope scope = VarScope.Product)
{
Variables.Add(GlobalVariableModel.Create(dataType, scope, Variables.Count));
}
///
/// 按名称写入变量值,供插件/通讯/流程写入任意类型(object 变量可承载任何对象)。
/// 变量不存在时返回 false。写入后自动触发 VariablesChanged → ResultRegistry 刷新公式数据。
///
public bool SetValue(string varName, object value)
{
if (string.IsNullOrWhiteSpace(varName)) return false;
var v = Variables.FirstOrDefault(x => x.Name == varName);
if (v == null) return false;
v.Value = value;
return true;
}
public object GetValue(string varName)
{
var v = Variables.FirstOrDefault(x => x.Name == varName);
return v?.Value;
}
public void DeleteVariable(GlobalVariableModel variable)
{
if (variable == null) return;
int idx = Variables.IndexOf(variable);
if (idx < 0) return;
Variables.RemoveAt(idx);
Reindex();
}
public void MoveUp(GlobalVariableModel variable)
{
if (variable == null) return;
int idx = Variables.IndexOf(variable);
if (idx <= 0) return;
Variables.Move(idx, idx - 1);
Reindex();
}
public void MoveDown(GlobalVariableModel variable)
{
if (variable == null) return;
int idx = Variables.IndexOf(variable);
if (idx >= Variables.Count - 1) return;
Variables.Move(idx, idx + 1);
Reindex();
}
private void Reindex()
{
for (int i = 0; i < Variables.Count; i++)
Variables[i].Index = i;
}
public Dictionary GetAllValuesDict()
{
var dict = new Dictionary();
foreach (var v in Variables)
{
if (!string.IsNullOrWhiteSpace(v.Name))
dict[v.Name] = v.Value;
}
return dict;
}
public Dictionary> GetAsResultRegistryFormat()
{
var nodeDict = new Dictionary();
foreach (var v in Variables)
{
if (!string.IsNullOrWhiteSpace(v.Name))
nodeDict[v.Name] = v.Value;
}
return new Dictionary>
{
["GlobalVariables"] = nodeDict
};
}
#endregion
#region 作用域克隆 / 提交(供编辑器 克隆-编辑-提交,取消可回滚)
/// 返回指定作用域变量的深拷贝列表(编辑器工作集,改动不影响 live)。
public List CloneScoped(VarScope scope)
=> Variables.Where(v => v.Scope == scope).Select(v => v.Clone()).ToList();
///
/// 用给定项替换 live 中该作用域的全部变量(另一作用域保持不动)。
/// 会触发 CollectionChanged → VariablesChanged,ResultRegistry 已订阅并自动刷新公式数据。
/// 必须在 UI 线程调用(Variables 绑定 UI)。
///
public void ReplaceScoped(VarScope scope, IEnumerable items)
{
for (int i = Variables.Count - 1; i >= 0; i--)
if (Variables[i].Scope == scope) Variables.RemoveAt(i);
if (items != null)
foreach (var v in items)
{
v.Scope = scope; // 统一盖章,防外部传入 Scope 不一致
Variables.Add(v);
}
Reindex();
}
#endregion
#region 持久化:Global 机器级 / Product 产品级子集
/// 机器级 Global 变量文件:Config\global_vars.json。
public static string GlobalFixedVarsFile => TeamAAS.PathHelper.GlobalFixedVarsFile;
/// 启动时载入机器级 Global 变量(替换 live 列表中的 Global 子集)。
public void LoadGlobalScoped()
{
try
{
var list = new List();
var path = GlobalFixedVarsFile;
if (File.Exists(path))
{
var json = File.ReadAllText(path);
list = JsonConvert.DeserializeObject>(json) ?? new List();
}
foreach (var v in list) v.Scope = VarScope.Global;
ReplaceScoped(VarScope.Global, list);
}
catch { }
}
/// 把 live 列表中 Global 子集写入机器级文件。
public void SaveGlobalScoped()
{
try
{
var path = GlobalFixedVarsFile;
var dir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
var list = Variables.Where(v => v.Scope == VarScope.Global).ToList();
File.WriteAllText(path, JsonConvert.SerializeObject(list, Formatting.Indented));
}
catch { }
}
/// 把 live 列表中 Product 子集序列化到指定产品快照文件。
public void SaveSnapshot(string filePath)
{
try
{
var dir = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
var snap = new GlobalVarSnapshot
{
Variables = Variables.Where(v => v.Scope == VarScope.Product).ToList()
};
File.WriteAllText(filePath, JsonConvert.SerializeObject(snap, Formatting.Indented));
}
catch { }
}
///
/// 从产品快照恢复 Product 子集(Global 子集保持不动)。
/// 文件不存在(老产品没存过)时清空 Product 子集——切到新产品应从空开始,而非继承上个产品的变量。
/// 必须在 UI 线程调用。
///
public bool LoadSnapshot(string filePath)
{
try
{
var list = new List();
if (File.Exists(filePath))
{
var json = File.ReadAllText(filePath);
var snap = JsonConvert.DeserializeObject(json);
list = snap?.Variables ?? new List();
}
foreach (var v in list) v.Scope = VarScope.Product;
ReplaceScoped(VarScope.Product, list);
return File.Exists(filePath);
}
catch { return false; }
}
#endregion
/// 读取某产品快照文件的 Product 变量(不改 live 列表);文件不存在返回空列表。
public List ReadSnapshotList(string filePath)
{
try
{
if (!File.Exists(filePath)) return new List();
var snap = JsonConvert.DeserializeObject(File.ReadAllText(filePath));
var list = snap?.Variables ?? new List();
foreach (var v in list) v.Scope = VarScope.Product;
return list;
}
catch { return new List(); }
}
/// 把给定 Product 变量写入某产品快照文件(不改 live 列表)。
public void WriteSnapshotList(string filePath, IEnumerable items)
{
try
{
var dir = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
var list = (items ?? Enumerable.Empty()).ToList();
foreach (var v in list) v.Scope = VarScope.Product;
var snap = new GlobalVarSnapshot { Variables = list };
File.WriteAllText(filePath, JsonConvert.SerializeObject(snap, Formatting.Indented));
}
catch { }
}
/// 加载全局事件配置(心跳 / 产品切换事件)。静态,与变量作用域无关。
public static GlobalEventConfig LoadGlobalEventConfig()
{
try
{
var path = TeamAAS.PathHelper.GlobalEventConfigFile;
if (!File.Exists(path)) return new GlobalEventConfig();
var json = File.ReadAllText(path);
return JsonConvert.DeserializeObject(json) ?? new GlobalEventConfig();
}
catch { return new GlobalEventConfig(); }
}
}
}