Files

215 lines
7.0 KiB
C#

using StandardScene.Magnetic.Protocol;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace StandardScene.Magnetic.Tasking
{
/// <summary>
/// 管控停止(StartStop=12)按车放行:地图站点保持 12,仅改本车任务报文。
/// </summary>
public sealed class Fass2ControlAreaInfo
{
public int SiteId { get; set; }
public string AreaId { get; set; } = string.Empty;
public int[] AreaSiteIds { get; set; } = Array.Empty<int>();
public int Capacity { get; set; } = 1;
public byte ReleaseStartStop { get; set; } = Fass2TaskBuilder.StartStopControlStart;
}
public sealed class Fass2ControlOccupancy
{
public Fass2ControlOccupancy(int carId, IReadOnlyList<int> occupiedSiteIds)
{
CarId = carId;
OccupiedSiteIds = occupiedSiteIds ?? Array.Empty<int>();
}
public int CarId { get; }
public IReadOnlyList<int> OccupiedSiteIds { get; }
}
public sealed class Fass2ControlReleaseCheck
{
public bool CanRelease { get; set; }
public string AreaId { get; set; } = string.Empty;
public int Capacity { get; set; } = 1;
public int OthersInArea { get; set; }
public byte ReleaseStartStop { get; set; } = Fass2TaskBuilder.StartStopControlStart;
public string Reason { get; set; } = string.Empty;
}
public static class Fass2ControlAreaGate
{
private static readonly char[] SiteIdSeparators = { ',', ';', '|', ' ', '\t', '[', ']', '(', ')', '{', '}' };
public static bool IsControlStop(byte startStop)
{
return startStop == Fass2TaskBuilder.StartStopControlStop;
}
public static bool AllowsLeave(byte startStop)
{
return startStop == Fass2TaskBuilder.StartStopPass
|| startStop == Fass2TaskBuilder.StartStopControlStart;
}
public static Fass2ControlAreaInfo Resolve(Fass2SiteActionData data, int siteId)
{
data ??= new Fass2SiteActionData();
var areaSites = ParseSiteIds(data.ControlArea, siteId);
var capacity = data.ControlCapacity.GetValueOrDefault(1);
if (capacity < 1)
{
capacity = 1;
}
var release = data.ControlReleaseStartStop ?? Fass2TaskBuilder.StartStopControlStart;
if (release != Fass2TaskBuilder.StartStopPass &&
release != Fass2TaskBuilder.StartStopControlStart)
{
release = Fass2TaskBuilder.StartStopControlStart;
}
return new Fass2ControlAreaInfo
{
SiteId = siteId,
AreaSiteIds = areaSites,
AreaId = string.Join(",", areaSites),
Capacity = capacity,
ReleaseStartStop = release
};
}
public static int[] ParseSiteIds(string text, int fallbackSiteId)
{
var ids = new List<int>();
if (!string.IsNullOrWhiteSpace(text))
{
var parts = text.Split(SiteIdSeparators, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
{
if (int.TryParse(part.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var id) &&
id > 0 && !ids.Contains(id))
{
ids.Add(id);
}
}
}
if (ids.Count == 0 && fallbackSiteId > 0)
{
ids.Add(fallbackSiteId);
}
return ids.ToArray();
}
public static int LimitWindowCount(
IReadOnlyList<Fass2NodeMessage> nodes,
int startIndex,
int count,
int releasedIndex)
{
if (nodes == null || count <= 0 || startIndex < 0 || startIndex >= nodes.Count)
{
return 0;
}
var limited = Math.Min(count, nodes.Count - startIndex);
for (var i = 0; i < limited; i++)
{
var node = nodes[startIndex + i];
if (node != null && IsControlStop(node.StartStop) && releasedIndex != startIndex + i)
{
return i + 1;
}
}
return limited;
}
public static Fass2ControlReleaseCheck Evaluate(
int selfCarId,
Fass2ControlAreaInfo area,
IReadOnlyList<Fass2ControlOccupancy> occupancies)
{
area ??= new Fass2ControlAreaInfo();
if (area.AreaSiteIds == null || area.AreaSiteIds.Length == 0)
{
area.AreaSiteIds = area.SiteId > 0 ? new[] { area.SiteId } : Array.Empty<int>();
}
if (string.IsNullOrEmpty(area.AreaId))
{
area.AreaId = string.Join(",", area.AreaSiteIds);
}
if (area.Capacity < 1)
{
area.Capacity = 1;
}
var others = 0;
if (occupancies != null)
{
foreach (var occupancy in occupancies)
{
if (occupancy == null || occupancy.CarId == selfCarId)
{
continue;
}
if (OccupiesListedSites(occupancy.OccupiedSiteIds, area.AreaSiteIds))
{
others++;
}
}
}
var canRelease = others < area.Capacity;
return new Fass2ControlReleaseCheck
{
CanRelease = canRelease,
AreaId = area.AreaId,
Capacity = area.Capacity,
OthersInArea = others,
ReleaseStartStop = area.ReleaseStartStop == 0
? Fass2TaskBuilder.StartStopControlStart
: area.ReleaseStartStop,
Reason = canRelease
? "area clear"
: $"area occupied cars={others}, capacity={area.Capacity}"
};
}
public static bool OccupiesListedSites(IReadOnlyList<int> occupiedSiteIds, IReadOnlyList<int> areaSiteIds)
{
if (occupiedSiteIds == null || occupiedSiteIds.Count == 0 ||
areaSiteIds == null || areaSiteIds.Count == 0)
{
return false;
}
for (var i = 0; i < occupiedSiteIds.Count; i++)
{
var occupied = occupiedSiteIds[i];
if (occupied <= 0)
{
continue;
}
for (var j = 0; j < areaSiteIds.Count; j++)
{
if (areaSiteIds[j] == occupied)
{
return true;
}
}
}
return false;
}
}
}