using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace axXez.TS3.Protocol
{
/// Parsed TeamSpeak text-protocol message — includes the command name and all key-value entries.
public class TsMessage
{
/// The command or notification name (e.g. "clientlist", "notifyclientmoved").
public string Name { get; set; }
/// All parsed key-value entry sets. Multiple entries are separated by | in the raw data.
public List Entries { get; set; }
/// The raw message string, before parsing.
public string RawData { get; private set; }
/// Whether the message contains at least one data entry.
public bool HasData => Entries?.Count > 0;
/// Number of entries in the message.
public int Count => Entries?.Count ?? 0;
/// Shorthand for the first entry. null if is false.
public TsDataEntry Params => HasData ? Entries[0] : null;
/// Returns the entry at the given index.
public TsDataEntry this[int index] => Entries[index];
/// Returns the value of the given key from the first entry, or null if there is no data.
public string this[string key] => HasData ? Entries[0][key] : null;
internal TsMessage() { }
internal TsMessage(string name, string data)
{
Name = name;
RawData = data;
ParseEntries(data);
}
/// Parses a raw TeamSpeak text-protocol string into a .
public static TsMessage Parse(string raw)
{
var parts = raw.Split('|');
var first = parts[0].Trim();
int nameEnd = first.IndexOf(' ');
var name = nameEnd >= 0 ? first[..nameEnd] : first;
var entries = new List();
foreach (var part in parts)
entries.Add(TsDataEntry.Parse(part));
return new TsMessage { Name = name, RawData = raw, Entries = entries };
}
private void ParseEntries(string data)
{
if (string.IsNullOrWhiteSpace(data))
{
Entries = null;
return;
}
Entries = new();
foreach (var part in data.Split('|'))
Entries.Add(TsDataEntry.Parse(part));
}
/// Returns the value of the first matching key from the first entry, or an empty string if not found.
public string Get(params string[] keys)
=> HasData ? Entries[0].GetValue(keys) : "";
/// Returns the numeric value of the first matching key from the first entry, or the type's default if not found.
public T Get(params string[] keys) where T : INumber
=> HasData ? Entries[0].GetValue(keys) : default;
/// Deserializes the first entry into a of type .
public T Get() where T : TsEntity
=> HasData ? Entries[0].GetEntity() : default;
/// Returns the Unix-timestamp field from the first entry as a .
public DateTime GetDateTime(params string[] keys)
=> HasData ? Entries[0].GetDateTime(keys) : default;
/// Returns the value of the first matching key from every entry.
public List GetAll(params string[] keys)
=> HasData ? Entries.Select(x => x.GetValue(keys)).ToList() : [];
/// Returns the numeric value of the first matching key from every entry.
public List GetAll(params string[] keys) where T : INumber
=> HasData ? Entries.Select(x => x.GetValue(keys)).ToList() : [];
/// Deserializes every entry into a of type .
public List GetAll() where T : TsEntity
=> HasData ? Entries.Select(x => x.GetEntity()).ToList() : [];
internal Dictionary ToDictionary()
=> HasData ? Entries[0].ToDictionary() : new();
internal List> ToDictionaryList()
=> HasData ? Entries.Select(e => e.ToDictionary()).ToList() : new();
}
}