118 lines
4.4 KiB
C#
118 lines
4.4 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection.PortableExecutable;
|
|
using System.Threading.Tasks;
|
|
using BattSim.Models;
|
|
using Microsoft.AspNetCore.Components.Forms;
|
|
|
|
namespace BattSim.Services
|
|
{
|
|
public static class FluviusDataHandler
|
|
{
|
|
public static async Task<EnergyData[]> LoadAndProcessFile(IBrowserFile file)
|
|
{
|
|
var lines = await ReadCsvFile(file);
|
|
var energyData = new ConcurrentDictionary<DateTime,EnergyData>(); // Thread-safe collection
|
|
// Process lines in parallel
|
|
Parallel.ForEach(lines, line =>
|
|
{
|
|
try
|
|
{
|
|
var parts = SplitLine(line);
|
|
DateTime time = ParseDateTime(parts[..2]);
|
|
double volume = ParseVolume(parts[8]);
|
|
string register = parts[7].Trim();
|
|
bool dayTarif = register.Contains("Dag");
|
|
|
|
var entry = new EnergyData { Time = time, DayTariff = dayTarif };
|
|
if (register.Contains("Afname"))
|
|
entry.Consumption = volume;
|
|
else if (register.Contains("Injectie"))
|
|
entry.Production = volume;
|
|
else
|
|
throw new Exception("Unknown volume register");
|
|
|
|
energyData.AddOrUpdate(entry.Time, entry, (_, existing) =>
|
|
{
|
|
existing.Consumption += entry.Consumption;
|
|
existing.Production += entry.Production;
|
|
return existing;
|
|
});
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine($"Error parsing line: {line}. Skipping to next line. Exception: {e}");
|
|
}
|
|
});
|
|
var results = energyData.Values.ToArray();
|
|
results.Sort((a,b)=>a.Time.CompareTo(b.Time));
|
|
return results;
|
|
}
|
|
|
|
public static EnergyData[] GenerateDailyData(EnergyData[] energyData)
|
|
{
|
|
var dailyEnergyData = new ConcurrentDictionary<DateOnly, EnergyData>();
|
|
Parallel.ForEach(energyData, energy =>
|
|
{
|
|
var date = DateOnly.FromDateTime(energy.Time);
|
|
|
|
// Use AddOrUpdate to avoid double lookup
|
|
dailyEnergyData.AddOrUpdate(
|
|
date,
|
|
new EnergyData(energy), // If key doesn't exist, add this value
|
|
(_, existing) =>
|
|
{
|
|
// If key exists, aggregate the values
|
|
existing.Consumption += energy.Consumption;
|
|
existing.Production += energy.Production;
|
|
return existing;
|
|
}
|
|
);
|
|
});
|
|
return dailyEnergyData.Values.ToArray();
|
|
}
|
|
|
|
private static async Task<List<string>> ReadCsvFile(IBrowserFile file)
|
|
{
|
|
await using var stream = file.OpenReadStream(maxAllowedSize: (int)1.0e9);
|
|
using var reader = new StreamReader(stream, bufferSize: (int)1.0e6);
|
|
|
|
// Skip header
|
|
await reader.ReadLineAsync();
|
|
// Read all lines into memory
|
|
var lines = new List<string>();
|
|
string line;
|
|
while ((line = await reader.ReadLineAsync()) is not null)
|
|
{
|
|
lines.Add(line);
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
private static string[] SplitLine(string line)
|
|
{
|
|
var parts = line.Split(';');
|
|
if (parts.Length < 9)
|
|
throw new Exception($"Malformed line (too many parts): {line}");
|
|
return parts;
|
|
}
|
|
|
|
private static DateTime ParseDateTime(string[] dateTimeStrings)
|
|
{
|
|
string dateTimeString = dateTimeStrings[0] + " " + dateTimeStrings[1];
|
|
return DateTime.ParseExact(dateTimeString, "dd-MM-yyyy HH:mm:ss", CultureInfo.GetCultureInfo("nl-BE"));
|
|
}
|
|
|
|
private static double ParseVolume(string volumeString)
|
|
{
|
|
var volumeStr = volumeString.Trim();
|
|
return string.IsNullOrEmpty(volumeStr)
|
|
? 0
|
|
: double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
} |