using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace RoboidControl {
///
/// A participant is a device which manages things.
///
/// It can communicate with other participant to synchronise the state of things.
/// This class is used to register the things the participant is managing.
/// It also maintains the communcation information to contact the participant.
/// It is used as a basis for the local participant, but also as a reference to remote participants.
public class Participant {
///
/// Create a new participant with the given communcation info
///
/// The IP address of the participant
/// The UDP port of the participant
public Participant(string ipAddress, int port) {
this.ipAddress = ipAddress;
this.port = port;
}
///
/// The Ip Address of a participant. When the participant is local, this contains 0.0.0.0
///
public string ipAddress = "0.0.0.0";
///
/// The port number for UDP communication with the participant. This is 0 for isolated participants.
///
public int port = 0;
///
/// he network Id to identify the participant
///
public byte networkId = 0;
///
/// The things managed by this participant
///
public readonly List things = new();
///
/// Get the thing with the given properties
///
/// The ID of the thing
/// The thing when it is found, null in other cases.
public Thing Get(byte thingId) {
Thing thing = things.Find(aThing => aThing.id == thingId);
//Thing thing = things.Find(aThing => Thing.IsThing(aThing, networkId, thingId));
// if (thing == null)
// Console.WriteLine($"Could not find thing {ipAddress}:{port}[{networkId}/{thingId}]");
return thing;
}
///
/// Add a new thing for this participant
///
/// The thing to add
/// If true, the thing.id is regenerated if it is zero
public void Add(Thing thing, bool checkId = true) {
if (checkId && thing.id == 0) {
thing.id = (byte)(this.things.Count + 1);
this.things.Add(thing);
}
else {
Thing foundThing = Get(thing.id);
if (foundThing == null)
this.things.Add(thing);
}
}
///
/// Remove a thing for this participant
///
/// The thing to remove
public void Remove(Thing thing) {
this.things.Remove(thing);
}
#region Update
///
/// Update all things for this participant
///
/// The current time in milliseconds (optional)
public virtual void Update(ulong currentTimeMS = 0) {
int n = this.things.Count;
for (int ix = 0; ix < n; ix++) {
Thing thing = this.things[ix];
if (thing != null)
thing.Update(currentTimeMS, true);
}
}
public class UpdateEvent {
public int messageId; // see the communication messages
public Thing thing;
public Participant participant;
}
public ConcurrentQueue updateQueue = new();
#endregion Update
///
/// The collection of known participants.
///
public readonly static List participants = new();
///
/// Retrieve a participant using ip address and port number
///
/// The ip address of the participant
/// The port number used to send messages to the participant
/// The participant or null if it is not found.
public static Participant GetParticipant(string ipAddress, int port) {
//Console.WriteLine($"Get Participant {ipAddress}:{port}");
foreach (Participant participant in Participant.participants) {
if (participant.ipAddress == ipAddress && participant.port == port)
return participant;
}
return null;
}
///
/// Retrieve a participant using a network ID
///
/// The network ID of the participant
/// The participant or null if it is not found.
public static Participant GetParticipant(int networkId) {
//Console.WriteLine($"Get Participant [networkId]");
foreach (Participant participant in Participant.participants) {
if (participant.networkId == networkId)
return participant;
}
return null;
}
///
/// Add a new participant to the collection of participants
///
/// The IP address of the participant
/// The port used to send messages to this participant
/// The added participant
public static Participant AddParticipant(string ipAddress, int port) {
Console.WriteLine($"New Participant {ipAddress}:{port}");
Participant participant = new(ipAddress, port) {
networkId = (byte)(Participant.participants.Count + 1)
};
Participant.participants.Add(participant);
return participant;
}
///
/// Add a new participant to the collection of participants
///
/// The participant to add
/// This function only adds the participant if it is not yet in the collection
public static void AddParticipant(Participant participant) {
Participant foundParticipant = Participant.GetParticipant(participant.networkId);
if (foundParticipant == null)
Participant.participants.Add(participant);
}
}
}