using System.Reflection;
using adas_core.Domain.Enums;
using MongoDB.Bson;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace adas_core.Domain.Models.MongoModels;
///
/// Represents a custom JSON converter for serializing and deserializing historical configuration changes.
///
///
/// This converter extends to provide tailored JSON conversion behavior for historical config change data.
///
public class HistoricalConfigChanges : JsonConverter
{
public DateTime Time;
public string Username = string.Empty;
public ObjectId Id { get; set; }
public DisplayConfigEnums.ConfigTypes? ConfigType { get; set; }
public string? OldConfig { get; set; }
public string NewConfig { get; set; } = string.Empty;
///
/// Serializes the specified object to JSON, skipping output when the value is null.
/// The object is first projected into a and annotated with a string enum converter for the ConfigType property before being written to the .
///
/// The that receives the serialized JSON output.
/// The object to serialize. If null, the method does nothing.
/// The used during serialization.
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value != null)
{
var jo = JObject.FromObject(value);
AddStringEnumConverterAttribute(value, nameof(ConfigType));
jo.WriteTo(writer);
}
}
///
/// Adds a using to the specified property via reflection, but only if the property does not already have a applied. The new attribute is appended to the existing custom attributes array using a non-public field on .
///
/// The object instance whose type defines the target property.
/// The name of the property to which the converter attribute should be added.
private static void AddStringEnumConverterAttribute(object value, string propertyName)
{
var prop = value.GetType().GetProperty(propertyName);
var attr = new JsonConverterAttribute(typeof(StringEnumConverter));
if (prop != null)
{
var attrs = prop.GetCustomAttributes(false);
// Check if the attribute is not already applied
if (Array.Find(attrs, a => a is JsonConverterAttribute) == null)
{
// Create a new array that includes the existing attributes and the new one
var newAttrs = new object[attrs.Length + 1];
Array.Copy(attrs, newAttrs, attrs.Length);
newAttrs[attrs.Length] = attr;
// Use reflection to set the new attributes array
var field = typeof(PropertyInfo).GetField("m_customAttributes",
BindingFlags.Instance | BindingFlags.NonPublic);
field?.SetValue(prop, newAttrs);
}
}
}
///
/// Reads the JSON representation of the object and converts it to the target type as part of a custom . This implementation is not yet provided.
///
/// The used to read the JSON content.
/// The type of the object to deserialize to.
/// The existing value of the object being read, or null if no value exists.
/// The used to deserialize nested objects.
/// The deserialized object value.
/// Always thrown because the method has not been implemented.
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
///
/// Determines whether the converter can convert the specified type. The override has not been implemented and always throws a when invoked.
///
/// The type to evaluate for convertibility.
/// when the converter supports ; otherwise, .
/// Thrown in all cases because the method body is not implemented.
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}