using HandyControl.Tools.Extension;
using PropertyGridLib.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using TeamAAS.Communication;
using TeamAAS.FlowEditor.Execution;
using TeamAAS.FlowEditor.Models;
using TeamAAS.FlowEngine;
namespace TeamAAS.FlowEngine.FormulaData
{
///
/// 普通节点属性的公式树数据源。基于当前选中节点 的上下文,
/// 提供三类节点:全局变量(Gloab)、组合模块输入参数(输入)、当前流程所有前置节点输出结果。
/// 自动处理「编辑组合模块内部节点」「编辑组合模块输出属性」「编辑主流程普通节点」三种场景。
///
[Serializable]
public class PluginDataProvider : IFormulaTreeProvider
{
///
/// 生成公式树节点列表,按 上下文过滤前置节点。
///
public List GetFormulaTree(PropertyItem propertyItem)
{
var nodes = new List();
try
{
Dictionary> flowResults;
string findId;
string findName = PluginLoader.Instance.SelectFlow.NodeName;
FlowGraph graph = null;
if (PluginLoader.Instance.SetGroupPluginModel != null)
{
// 编辑组合模块内部节点 — 查 SubGraph 结果(所有节点均为前置,不做过滤)
findId = PluginLoader.Instance.SetGroupPluginModel.GraphId;
findName = PluginLoader.Instance.SetGroupPluginModel.GraphName;
graph = PluginLoader.Instance.SetGroupPluginModel;
}
else if (PluginLoader.Instance.SelectFlow.ToolName == "组合模块")
{
// 编辑组合模块输出属性 — 查 SubGraph 结果,全部节点均为前置
findId = PluginLoader.Instance.SelectFlow.NodeId;
}
else
{
// 普通节点 — 查当前流程结果(key=GraphId)
findId = PluginLoader.Instance.SelectFlow.FlowId;
var tab = PluginLoader.Instance.FlowTabs.FirstOrDefault(t => t.Graph != null && t.Graph.GraphId == findId);
graph = tab != null ? tab.Graph : null;
// 回退查找:子节点的 FlowId 是 SubGraph 的 GraphId,不在 FlowTabs 中
if (graph == null)
{
foreach (var t in PluginLoader.Instance.FlowTabs)
{
if (t?.Graph == null) continue;
graph = FindSubGraphById(t.Graph, findId);
if (graph != null) break;
}
}
}
// 使用选中节点所属流程绑定的注册表(编辑态=Debug,监控态挂接运行图=Main)
var registry = PluginLoader.Instance.SelectFlow?.Registry ?? ResultRegistry.Debug;
registry.GetFlowResults(findId, out flowResults);
// 可见节点名集合(绑定树的一级节点):
// - 普通节点:反向追溯到的前置节点(即使尚未运行、registry 无结果也可见 → 支持“跑之前就能绑”)
// - 编辑组合模块内部:全部子节点均为前置
// - 拿不到 graph 时:退回运行时结果键(保持旧行为)
HashSet visibleNodes;
if (PluginLoader.Instance.SetGroupPluginModel == null)
{
flowResults.DeleteIfExistsKey(findName);
if (graph != null && PluginLoader.Instance.SelectFlow != null)
visibleNodes = GetPredecessorNodeNames(graph, PluginLoader.Instance.SelectFlow.NodeId);
else
visibleNodes = new HashSet(flowResults.Keys);
}
else
{
visibleNodes = new HashSet(flowResults.Keys);
if (graph != null)
foreach (var n in graph.Nodes)
if (!string.IsNullOrEmpty(n?.NodeName)) visibleNodes.Add(n.NodeName);
}
// 声明 schema:节点名 -> (输出键 -> 声明类型),取自各节点插件的 DeclareOutputs()
var schemaByName = new Dictionary>();
if (graph != null)
{
foreach (var n in graph.Nodes)
{
if (n?.PluginModel == null || !visibleNodes.Contains(n.NodeName)) continue;
var dict = new Dictionary();
try
{
foreach (var f in n.PluginModel.DeclareOutputs())
if (f != null && !string.IsNullOrEmpty(f.Key)) dict[f.Key] = f.ValueType;
}
catch { }
schemaByName[n.NodeName] = dict;
}
}
if (propertyItem.Value == null)
propertyItem.Value = new object();
var targetType = propertyItem.Value.GetType();
var formulaType = propertyItem.PropertyType;
foreach (var nodeName in visibleNodes)
{
if (string.IsNullOrEmpty(nodeName)) continue;
flowResults.TryGetValue(nodeName, out var runtime);
schemaByName.TryGetValue(nodeName, out var declared);
// 合并“声明键 + 运行时键”;有效类型优先取运行时值类型,值为空则回退到声明类型
var merged = new Dictionary();
if (declared != null)
foreach (var kv in declared) merged[kv.Key] = kv.Value;
if (runtime != null)
foreach (var kv in runtime)
merged[kv.Key] = kv.Value != null
? kv.Value.GetType()
: (merged.TryGetValue(kv.Key, out var dt) ? dt : null);
var children = merged
.Where(kv => targetType == null || targetType == typeof(object)
|| (kv.Value != null && (kv.Value == targetType || kv.Value == formulaType)))
.Select(kv => new FormulaTreeNode
{
Header = kv.Key,
Formula = $"&{{{nodeName}.{kv.Key}}}"
}).ToList();
if (children.Count == 0) continue;
nodes.Add(new FormulaTreeNode { Header = nodeName, Children = children });
}
// ========== 全局变量节点 ==========
try
{
registry.RefreshGlobalVariables();
var gloabNode = new FormulaTreeNode
{
Header = "Gloab",
Children = GlobalVariableManager.Instance.Variables
.Where(v => !string.IsNullOrWhiteSpace(v.Name))
.Select(v => new FormulaTreeNode
{
Header = v.Name,
Formula = $"&{{Gloab.{v.Name}}}"
}).ToList()
};
if (gloabNode.Children.Count > 0)
nodes.Insert(0, gloabNode);
}
catch { }
// ========== 输入参数节点(组合模块内部) ==========
try
{
if (PluginLoader.Instance.SetGroupPluginModel == null)
{
var inputsNode = BuildInputsNode(propertyItem);
if (inputsNode != null && inputsNode.Children.Count > 0)
nodes.Insert(0, inputsNode);
}
}
catch { }
}
catch { }
return nodes;
}
///
/// 构建「输入」参数公式树节点 — 从 的 ModuleInputs 反射读取。
/// 用于组合模块内部节点属性编辑。
///
private static FormulaTreeNode BuildInputsNode(PropertyItem propertyItem)
{
var parent = PluginLoader.Instance.ParentGroupModel;
if (parent == null) return null;
var moduleInputsProp = parent.GetType().GetProperty("ModuleInputs");
if (moduleInputsProp == null) return null;
var inputs = moduleInputsProp.GetValue(parent) as System.Collections.IList;
if (inputs == null || inputs.Count == 0) return null;
var targetType = propertyItem?.Value?.GetType();
var formulaType = propertyItem?.PropertyType;
var children = new List();
foreach (var item in inputs)
{
if (item == null) continue;
var nameProp = item.GetType().GetProperty("InputName");
var dataTypeProp = item.GetType().GetProperty("DataType");
var inputName = nameProp?.GetValue(item) as string;
var dataType = dataTypeProp?.GetValue(item) as string ?? "";
if (string.IsNullOrWhiteSpace(inputName)) continue;
if (targetType != null && targetType != typeof(object) && !string.IsNullOrEmpty(dataType))
{
try
{
var inputType = Type.GetType(dataType) ?? Type.GetType("System." + dataType + ", mscorlib");
if (inputType != null && inputType != typeof(object)
&& inputType != targetType && inputType != formulaType)
continue;
}
catch { }
}
children.Add(new FormulaTreeNode
{
Header = string.IsNullOrEmpty(dataType) ? inputName : $"{inputName} ({dataType})",
Formula = $"&{{输入.{inputName}}}"
});
}
if (children.Count == 0) return null;
return new FormulaTreeNode { Header = "输入", Children = children };
}
///
/// 在流程图中递归查找 GraphId 匹配的 SubGraph(支持嵌套组合模块)。
///
private static FlowGraph FindSubGraphById(FlowGraph parentGraph, string graphId)
{
foreach (var node in parentGraph.Nodes)
{
var model = node.PluginModel?.GetModel;
if (model == null) continue;
var graphProp = model.GetType().GetProperty("SubGraph");
if (graphProp != null)
{
var subGraph = graphProp.GetValue(model) as FlowGraph;
if (subGraph != null)
{
if (subGraph.GraphId == graphId) return subGraph;
var nested = FindSubGraphById(subGraph, graphId);
if (nested != null) return nested;
}
}
}
return null;
}
///
/// 获取指定节点的所有前置节点名称(通过连接线反向 BFS 追溯)。
///
private static HashSet GetPredecessorNodeNames(FlowGraph graph, string nodeId)
{
var predecessorIds = new HashSet();
var queue = new Queue();
// 从直接上游开始
foreach (var conn in graph.Connections)
{
if (conn.TargetNodeId == nodeId) queue.Enqueue(conn.SourceNodeId);
}
while (queue.Count > 0)
{
var current = queue.Dequeue();
if (predecessorIds.Add(current))
{
foreach (var conn in graph.Connections)
{
if (conn.TargetNodeId == current) queue.Enqueue(conn.SourceNodeId);
}
}
}
// NodeId -> NodeName
var result = new HashSet();
foreach (var node in graph.Nodes)
{
if (predecessorIds.Contains(node.NodeId))
result.Add(node.NodeName);
}
return result;
}
}
}