using System.Text.Json.Serialization; using System.Text.Json; using Microsoft.Extensions.Configuration; using Persistence.Models; using Persistence.Repositories; using Persistence.Services.Interfaces; using Persistence.Models.Configurations; using Persistence.Models.Enumerations; using System.Globalization; namespace Persistence.Services; public class WitsDataService : IWitsDataService { private readonly IParameterRepository witsDataRepository; private readonly WitsInfo[] witsInfo; private const int multiplier = 1000; private const string witsConfigPath = "Persistence.Services.Config.WitsConfig.json"; public WitsDataService(IParameterRepository witsDataRepository) { this.witsDataRepository = witsDataRepository; this.witsInfo = GetWitsInfo(); } public Task GetDatesRangeAsync(Guid idDiscriminator, CancellationToken token) { var result = witsDataRepository.GetDatesRangeAsync(idDiscriminator, token); return result; } public async Task> GetPart(Guid idDiscriminator, DateTimeOffset dateBegin, int take, CancellationToken token) { var dtos = await witsDataRepository.GetPart(idDiscriminator, dateBegin, take, token); var result = AdaptToWitsData(dtos); return result; } public async Task> GetValuesForGraph(Guid discriminatorId, DateTimeOffset dateFrom, DateTimeOffset dateTo, int approxPointsCount, CancellationToken token) { var intervalSec = (dateTo - dateFrom).TotalSeconds; int? ratio = null; if (intervalSec > 2 * approxPointsCount) { ratio = (int) intervalSec / approxPointsCount; } var dtos = await witsDataRepository.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointsCount, ratio, token); var result = AdaptToWitsData(dtos); return result; } public async Task AddRange(IEnumerable dtos, CancellationToken token) { var parameterDtos = dtos.SelectMany(e => e.Values.Select(t => new ParameterDto() { DiscriminatorId = e.DiscriminatorId, ParameterId = EncodeId(t.RecordId, t.ItemId), Value = t.Value.ToString()!, Timestamp = e.Timestamped })); var result = await witsDataRepository.AddRange(parameterDtos, token); return result; } private int EncodeId(int recordId, int itemId) { var resultId = multiplier * recordId + itemId; return resultId; } private int DecodeRecordId(int id) { var resultId = id / multiplier; return resultId; } private int DecodeItemId(int id) { var resultId = id % multiplier; return resultId; } private IEnumerable AdaptToWitsData(IEnumerable dtos) { var result = new List(); var witsGroup = dtos .GroupBy(e => new { e.DiscriminatorId, e.Timestamp }); foreach (var witsInGroup in witsGroup) { var witsDataDto = new WitsDataDto() { DiscriminatorId = witsInGroup.Key.DiscriminatorId, Timestamped = witsInGroup.Key.Timestamp }; witsDataDto.Values = witsInGroup.Select(e => { var recordId = DecodeRecordId(e.ParameterId); var itemId = DecodeItemId(e.ParameterId); return new WitsValueDto() { RecordId = recordId, ItemId = itemId, Value = ConvertValue(recordId, itemId, e.Value) }; }); result.Add(witsDataDto); } return result; } private object ConvertValue(int recordId, int itemId, string value) { var witsType = witsInfo.FirstOrDefault(e => e.ItemId == itemId && e.RecordId == recordId)?.ValueType; switch(witsType) { default: { return value; } case WitsType.S: { var result = Int16.Parse(value); return result; } case WitsType.L: { var result = Int32.Parse(value); return result; } case WitsType.F: { var result = float.Parse(value, CultureInfo.InvariantCulture); return result; } } } private WitsInfo[] GetWitsInfo() { var stream = System.Reflection.Assembly.GetExecutingAssembly() .GetManifestResourceStream(witsConfigPath); var options = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }, }; var records = JsonSerializer.Deserialize(stream!, options) ?? []; return records; } }