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, IConfiguration configuration) { this.witsDataRepository = witsDataRepository; this.witsInfo = GetWitsInfo(); } public Task GetDatesRangeAsync(int idDiscriminator, CancellationToken token) { var result = witsDataRepository.GetDatesRangeAsync(idDiscriminator, token); return result; } public async Task> GetPart(int 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(int 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(); foreach (var dto in dtos) { var witsDataDto = result.FirstOrDefault(e => e.DiscriminatorId == dto.DiscriminatorId && e.Timestamped == dto.Timestamp); if (witsDataDto == null) { witsDataDto = new WitsDataDto() { DiscriminatorId = dto.DiscriminatorId, Timestamped = dto.Timestamp }; result.Add(witsDataDto); } var recordId = DecodeRecordId(dto.ParameterId); var itemId = DecodeItemId(dto.ParameterId); var witsValueDto = new WitsValueDto() { RecordId = recordId, ItemId = itemId, Value = ConvertValue(recordId, itemId, dto.Value) }; witsDataDto.Values.Append(witsValueDto); } 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; } }