using SimpleLite.RCS;
using SimpleCore;
using SimpleCore.PropType;
using System;
using System.Linq;
using SimpleLite.RCS.CarTypes;
namespace StandardScene.Scheduler.FassEvent
{
///
/// 节点(地标)交管判断辅助类,替代 FASS AlgorithmService 中与 EventCar 相关的方法。
///
/// “锁定”判定依据 StandardScene 交通锁:holdingLocks、pendingLocks、aquiringLock,
/// 以及站点 tags 中的 unavailable。
///
///
internal static class FassEventNodeHelper
{
/// 指定节点列表是否全部未被任何车辆占用。
public static bool NodeAllUnlocked(string[] nodeCodes)
{
return nodeCodes == null || nodeCodes.All(node => !IsNodeLocked(node, -1));
}
/// 指定节点列表是否全部未被占用(排除当前车辆自身锁)。
public static bool NodeAllUnlockedNotCar(string carCode, string[] nodeCodes)
{
var excludeCarId = ResolveCarId(carCode);
return nodeCodes == null || nodeCodes.All(node => !IsNodeLocked(node, excludeCarId));
}
/// 指定节点列表中是否存在任意一个被占用的节点。
public static bool NodeAnyLocked(string[] nodeCodes)
{
return nodeCodes != null && nodeCodes.Any(node => IsNodeLocked(node, -1));
}
/// 指定节点列表中是否存在被其他车辆占用的节点(排除自身)。
public static bool NodeAnyLockedNotCar(string carCode, string[] nodeCodes)
{
var excludeCarId = ResolveCarId(carCode);
return nodeCodes != null && nodeCodes.Any(node => IsNodeLocked(node, excludeCarId));
}
///
/// 节点全部解锁(排除自身)且指定节点范围内不存在处于运行态的其他车辆。
/// 对应 FASS NodeAllUnlockedNotCarNotEndCarState。
///
public static bool NodeAllUnlockedNotCarNotEndCarState(string carCode, string runningState, string[] nodeCodes)
{
if (!NodeAllUnlockedNotCar(carCode, nodeCodes))
{
return false;
}
return !ExistsRunningCarOnNodes(carCode, runningState, nodeCodes);
}
///
/// 判断除指定车辆外,是否有车辆在给定节点列表上处于“运行中”状态。
/// 逻辑对齐 FASS IsExistRunningStateCar:支持首参 Contains 匹配及 Skip(1) 尾节点匹配。
///
public static bool ExistsRunningCarOnNodes(string excludeCarCode, string runningState, string[] nodeCodes)
{
if (nodeCodes == null || nodeCodes.Length == 0)
{
return false;
}
var excludeCarId = ResolveCarId(excludeCarCode);
foreach (var car in SimpleLib.GetAllCars().OfType())
{
if (car.id == excludeCarId)
{
continue;
}
var currentNode = FassEventCarSnapshotFactory.GetCurrentNodeCode(car);
if (string.IsNullOrWhiteSpace(currentNode))
{
continue;
}
var state = FassEventCarSnapshotFactory.GetFassState(car);
if (!IsRunningState(state, runningState))
{
continue;
}
// 与 FASS 一致:当前地标包含参数首项,或等于后续任一项。
if (nodeCodes.Any(node => string.Equals(node, currentNode, StringComparison.OrdinalIgnoreCase)
|| currentNode.Contains(node)))
{
return true;
}
if (nodeCodes.Length > 1)
{
var tailNodes = nodeCodes.Skip(1).ToArray();
if (tailNodes.Any(node => string.Equals(node, currentNode, StringComparison.OrdinalIgnoreCase)))
{
return true;
}
}
}
return false;
}
///
/// 判断单个地标是否被锁定。
/// 节点号可解析为站点 ID,或通过 fields["TagValue"] 匹配地标标签。
///
private static bool IsNodeLocked(string nodeCode, int excludeCarId)
{
if (!TryResolveSiteId(nodeCode, out var siteId))
{
return false;
}
var site = SimpleLib.GetSite(siteId);
if (site?.tags?.Contains("unavailable") == true)
{
return true;
}
return SimpleLib.GetAllCars().Any(car =>
car.id != excludeCarId &&
(car.status.holdingLocks?.Contains(siteId) == true ||
car.status.pendingLocks?.Contains(siteId) == true ||
car.status.aquiringLock == siteId));
}
/// 根据 FASS 车辆编号解析场景内 car.id。
private static int ResolveCarId(string carCode)
{
if (string.IsNullOrWhiteSpace(carCode))
{
return -1;
}
var car = SimpleLib.GetAllCars()
.OfType()
.FirstOrDefault(item => string.Equals(FassEventCarSnapshotFactory.GetCarCode(item), carCode, StringComparison.OrdinalIgnoreCase));
return car?.id ?? -1;
}
///
/// 将地标编码解析为站点 ID:纯数字直接查站;否则按 TagValue 字段匹配。
///
private static bool TryResolveSiteId(string nodeCode, out int siteId)
{
siteId = 0;
if (string.IsNullOrWhiteSpace(nodeCode))
{
return false;
}
if (int.TryParse(nodeCode, out siteId))
{
return SimpleLib.GetSite(siteId) != null;
}
var site = SimpleLib.GetAllSites().FirstOrDefault(item =>
item.fields.TryGetValue("TagValue", out var tag) &&
string.Equals(tag, nodeCode, StringComparison.OrdinalIgnoreCase));
if (site == null)
{
return false;
}
siteId = site.id;
return true;
}
///
/// 判断状态是否视为“运行中”。兼容 FASS 历史拼写 Runing 与 Running。
///
private static bool IsRunningState(string state, string runningState)
{
if (string.IsNullOrWhiteSpace(state))
{
return false;
}
if (string.Equals(state, runningState, StringComparison.OrdinalIgnoreCase))
{
return true;
}
return string.Equals(state, "Running", StringComparison.OrdinalIgnoreCase) &&
(string.Equals(runningState, "Runing", StringComparison.OrdinalIgnoreCase) ||
string.Equals(runningState, "Running", StringComparison.OrdinalIgnoreCase));
}
}
}