using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TeamAAS.Robot.Core.Robots;
using TeamAAS.Robot.Interfaces;
using TeamAAS.Robot.Models;
using System.Reflection;
using TeamAAS.Robot.Attributes;
using TeamAAS.Robot.Enums;
namespace TeamAAS.Robot
{
///
/// 机器人生命周期管理器。懒汉单例:RobotManager.Instance。
/// 整合:设备创建/连接/运动/配置持久化 + 反射发现品牌类型 + IDisposable。
/// 管理类按架构规则保留在根命名空间 TeamAAS.Robot。
///
public class RobotManager : IRobotManager, IDisposable
{
#region 单例
private static readonly Lazy _instance =
new Lazy(() => new RobotManager(), isThreadSafe: true);
///
/// 懒汉单例入口。首次访问时初始化,线程安全。
///
public static RobotManager Instance => _instance.Value;
#endregion
private readonly Dictionary _robotCollection;
private readonly object _sync = new object();
private List _scannedTypes;
private readonly object _scanLock = new object();
public RobotManager()
{
_robotCollection = new Dictionary();
}
#region 机器人 CRUD
public bool CreateRobot(Guid id, RobotInfo robotInfo)
{
if (robotInfo == null) throw new ArgumentNullException(nameof(robotInfo));
var robot = CreateRobotInstance(robotInfo);
robot.Id = id;
IRobot replaced = null;
lock (_sync)
{
_robotCollection.TryGetValue(id, out replaced);
_robotCollection[id] = robot;
}
if (replaced != null && !ReferenceEquals(replaced, robot))
{
try { replaced.Dispose(); } catch { }
}
return true;
}
public Task CreateRobotAsync(Guid id, RobotInfo robotInfo)
{
return Task.Run(() => CreateRobot(id, robotInfo));
}
public IRobot GetRobot(Guid id)
{
lock (_sync)
{
return _robotCollection.TryGetValue(id, out var robot) ? robot : null;
}
}
public Task GetRobotAsync(Guid id)
{
return Task.Run(() => GetRobot(id));
}
public void UnRegisterRobot(Guid id)
{
IRobot robot = null;
lock (_sync)
{
if (_robotCollection.TryGetValue(id, out robot))
_robotCollection.Remove(id);
}
if (robot != null)
{
try { robot.Dispose(); } catch { }
}
}
public Task UnRegisterRobotAsync(Guid id)
{
return Task.Run(() => UnRegisterRobot(id));
}
public IReadOnlyCollection GetAllRobots()
{
lock (_sync)
{
return _robotCollection.Values.ToList().AsReadOnly();
}
}
public Task> GetAllRobotsAsync()
{
return Task.Run(() => GetAllRobots());
}
public bool TryGetRobot(Guid id, out IRobot robot)
{
lock (_sync)
{
return _robotCollection.TryGetValue(id, out robot);
}
}
public Task<(bool found, IRobot robot)> TryGetRobotAsync(Guid id)
{
return Task.Run(() =>
{
IRobot robot;
bool found;
lock (_sync)
{
found = _robotCollection.TryGetValue(id, out robot);
}
return (found, robot);
});
}
public System.Collections.Generic.IReadOnlyList Devices
{
get
{
lock (_sync)
{
return _robotCollection.Values.ToList().AsReadOnly();
}
}
}
public bool ContainsRobot(Guid id)
{
lock (_sync)
{
return _robotCollection.ContainsKey(id);
}
}
public Task ContainsRobotAsync(Guid id)
{
return Task.Run(() => ContainsRobot(id));
}
public bool RemoveRobot(Guid id)
{
IRobot robot = null;
lock (_sync)
{
if (_robotCollection.TryGetValue(id, out robot))
_robotCollection.Remove(id);
}
if (robot != null)
{
try { robot.Dispose(); } catch { }
return true;
}
return false;
}
public Task RemoveRobotAsync(Guid id)
{
return Task.Run(() => RemoveRobot(id));
}
public IRobot GetRobotByNumber(int robotNo)
{
return TryFindRobotByNumber(robotNo, out _, out var robot) ? robot : null;
}
public Task GetRobotByNumberAsync(int robotNo)
{
return Task.Run(() => GetRobotByNumber(robotNo));
}
public Task UnRegisterRobotByNumberAsync(int robotNo)
{
return Task.Run(() => UnRegisterRobotByNumber(robotNo));
}
public void UnRegisterRobotByNumber(int robotNo)
{
if (TryFindRobotByNumber(robotNo, out var id, out _))
UnRegisterRobot(id);
}
public void RemoveAllRobots()
{
List robotIds;
lock (_sync)
{
robotIds = _robotCollection.Keys.ToList();
}
foreach (var id in robotIds)
{
RemoveRobot(id);
}
}
public (bool IsSucceed, string Message) InitializeAllRobots(RobotInfo[] robots)
{
RemoveAllRobots();
foreach (var robotInfo in robots)
{
var robot = CreateRobotInstance(robotInfo);
lock (_sync)
{
_robotCollection[robot.Id] = robot;
}
}
bool allConnected = true;
StringBuilder errorMessages = new StringBuilder();
var allRobots = GetAllRobots();
foreach (var robot in allRobots)
{
try { robot.Connect(); } catch { }
if (!robot.IsConnected)
{
allConnected = false;
errorMessages.AppendLine($"机器人[{robot.Name}]连接失败。");
}
}
return allConnected ? (true, "所有机器人初始化并连接成功。") : (false, errorMessages.ToString());
}
public Task<(bool IsSucceed, string Message)> InitializeAllRobotsAsync(RobotInfo[] robots)
{
return Task.Run(() => InitializeAllRobots(robots));
}
public void UpdateRobotNumber(Guid id, int newNumber)
{
lock (_sync)
{
if (_robotCollection.TryGetValue(id, out var robot))
robot.RobotNo = newNumber;
}
}
private bool TryFindRobotByNumber(int robotNo, out Guid id, out IRobot robot)
{
lock (_sync)
{
foreach (var kvp in _robotCollection)
{
if (kvp.Value == null) continue;
if (kvp.Value.RobotNo == robotNo)
{
id = kvp.Key;
robot = kvp.Value;
return true;
}
}
}
id = Guid.Empty;
robot = null;
return false;
}
#endregion
#region 配置持久化
public static string DefaultConfigPath
{
get
{
return Path.Combine(TeamAAS.PathHelper.ConfigDirectory, "Robots.json");
}
}
public bool SaveConfig(string path = null)
{
path = path ?? DefaultConfigPath;
var infos = new List();
lock (_sync)
{
foreach (var robot in _robotCollection.Values)
{
infos.Add(new RobotInfo
{
Id = robot.Id,
RobotNo = robot.RobotNo,
RobotName = robot.Name,
RobotBrand = robot.Brand,
IP = robot.RobotIp,
Port = robot.RobotPort,
ConnectType = robot.ConnectType,
Terminator = robot.Terminator,
DataEncoding = robot.DataEncoding,
});
}
}
return TeamAAS.JsonFileStore.Save(path, infos);
}
public IReadOnlyList GetAllRobotInfos()
{
var infos = new List();
lock (_sync)
{
foreach (var robot in _robotCollection.Values)
{
infos.Add(new RobotInfo
{
Id = robot.Id,
RobotNo = robot.RobotNo,
RobotName = robot.Name,
RobotBrand = robot.Brand,
IP = robot.RobotIp,
Port = robot.RobotPort,
ConnectType = robot.ConnectType,
Terminator = robot.Terminator,
DataEncoding = robot.DataEncoding,
});
}
}
return infos.AsReadOnly();
}
public void LoadConfig(string path = null)
{
path = path ?? DefaultConfigPath;
if (!File.Exists(path)) return;
var infos = TeamAAS.JsonFileStore.Load>(path);
if (infos == null || infos.Count == 0) return;
InitializeAllRobots(infos.ToArray());
}
#endregion
#region 反射扫描 + 工厂
public IReadOnlyList GetAvailableTypes()
{
if (_scannedTypes != null) return _scannedTypes.AsReadOnly();
lock (_scanLock)
{
if (_scannedTypes != null) return _scannedTypes.AsReadOnly();
_scannedTypes = ScanTypes();
return _scannedTypes.AsReadOnly();
}
}
private List ScanTypes()
{
var result = new List();
// 通用模块扫描:收集全部 IRobot 实现(含 Runtime\Plugins 里的插件 DLL)
foreach (var type in TeamAAS.Modularity.AssemblyScanner.FindImplementations())
{
var attrs = type.GetCustomAttributes();
foreach (var attr in attrs)
{
result.Add(new RobotTypeInfo
{
TypeKey = type.FullName,
DisplayName = attr.DisplayName,
Brand = attr.Brand,
Description = attr.Description,
Type = type
});
}
}
return result
.GroupBy(t => t.TypeKey + "|" + t.Brand)
.Select(g => g.First())
.OrderBy(t => t.DisplayName)
.ToList();
}
private IRobot CreateRobotInstance(RobotInfo robotInfo)
{
if (robotInfo == null) throw new ArgumentNullException(nameof(robotInfo));
var types = GetAvailableTypes();
var match = types.FirstOrDefault(t => t.Brand == robotInfo.RobotBrand);
if (match == null)
{
// fallback 到 EPSON 实现(兼容未注册的品牌占位)
return new EpsonRobot(robotInfo);
}
return (IRobot)Activator.CreateInstance(match.Type, robotInfo);
}
#endregion
#region IDisposable
public void Dispose()
{
List robots;
lock (_sync)
{
robots = _robotCollection.Values.ToList();
_robotCollection.Clear();
}
foreach (var r in robots)
{
try { r.Dispose(); } catch { }
}
GC.SuppressFinalize(this);
}
#endregion
}
}