using GeoVLog.Core.Models;
using PureHDF;
using System;
using System.Collections.Generic;
namespace GeoVLog.Core.Hdf5;
///
/// Manages writing sensor data to an HDF5 log file.
/// Provides registration of sensors and thread-safe appending of records to the file.
///
public sealed class H5LogFileWriter : IDisposable
{
private readonly H5File _file;
private H5NativeWriter _writer; // Use H5NativeWriter instead of H5FileWriter (PureHDF 2.1.1)
private readonly Dictionary _map = new();
private readonly string _filePath;
private int _unflushedCount;
///
/// Number of records written since the last call.
///
public int UnflushedCount => _unflushedCount;
///
/// Initializes a new instance for writing log data to a given HDF5 file path.
/// Opens/creates the file structure in memory and prepares it for writing to disk.
///
/// The file path where the HDF5 log will be stored (will be created or overwritten).
public H5LogFileWriter(string path)
{
// Create a new HDF5 file structure in memory (root group)
_file = new H5File();
// Begin a write operation to the specified file on disk.
// In PureHDF 2.1.1, BeginWrite returns an H5NativeWriter instead of H5FileWriter:contentReference[oaicite:6]{index=6}.
_writer = _file.BeginWrite(path);
_filePath = path;
}
///
/// Registers a sensor data stream with this log file, creating the corresponding dataset.
///
/// The unique identifier of the sensor (from the domain model).
/// The HDF5 dataset path (e.g., "/Sensors/GPS") where this sensor's data will be stored.
/// If true, parsed data will be generated for each record and provided via the callback.
/// The schema/type of the sensor, indicating how to parse its data.
/// Optional callback invoked with the parsed record (and sensor ID) each time a new message is written (if parsing is enabled).
public void RegisterSensor(
SensorId id, string hdf5Path,
bool enableParse, SensorSchema schema,
Action? cb)
{
// Create or open the sensor's dataset (variable-length string dataset) and map a writer for it
_map[id] = new H5SensorWriter(_file, _writer, hdf5Path, enableParse, schema, cb);
}
///
/// Enables or disables parsing for an already registered sensor.
///
/// The sensor to update.
/// True to parse messages; false to disable parsing.
internal void SetParsingEnabled(SensorId id, bool enable)
{
if (_map.TryGetValue(id, out var writer))
{
writer.SetParsingEnabled(enable);
}
}
///
/// Writes a single sensor data record to the log file for the specified sensor.
///
/// The sensor identifier (must be registered via ).
/// The timestamp of the record (UTC).
/// The raw sensor message bytes (in UTF-8 encoding).
///
/// Appends a new entry to the sensor's dataset. The entry includes the timestamp and message text.
/// This method is thread-safe when called on different sensors concurrently because each sensor writer uses internal locking.
/// Note: PureHDF's internal writing may serialize writes to a single file:contentReference[oaicite:7]{index=7}.
///
public void Write(SensorId id, DateTime utc, ReadOnlySpan msg)
{
// Delegate the write to the respective sensor writer
_map[id].Write(id, utc, msg);
_unflushedCount++;
}
///
/// Flushes the in-memory data to disk without closing the log file, allowing logging to continue.
///
///
/// This operation finalizes the current write session by disposing the underlying HDF5 writer (ensuring all buffered data is written to disk),
/// and then immediately begins a new write session on the same file. All registered sensor datasets remain open, and subsequent records
/// will be appended after the data that was flushed. Use this periodically (based on time or record count) to limit data loss in case of a crash.
///
public void Flush()
{
// Dispose the current writer to flush all data to disk and close the file
_writer.Dispose();
// Begin a new write operation on the same file to continue logging
_writer = _file.BeginWrite(_filePath);
// Update all sensor writers to use the new writer instance
foreach (var sensorWriter in _map.Values)
{
sensorWriter.UpdateWriter(_writer);
}
_unflushedCount = 0;
}
///
/// Finalizes the HDF5 file writing by flushing data to disk and releasing resources.
///
public void Dispose()
{
// Dispose each sensor writer (currently they manage only in-memory dataset references)
foreach (var writer in _map.Values)
{
writer.Dispose();
}
// Flush and write the HDF5 file to disk by disposing the H5NativeWriter.
_writer.Dispose();
// Note: Disposing _writer completes the file write operation and closes the file.
}
}