#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Swan.Lite.Reflection;
using Swan.Mappers;
using Swan.Reflection;
namespace Swan {
///
/// Extension methods.
///
public static partial class Extensions {
///
/// Iterates over the public, instance, readable properties of the source and
/// tries to write a compatible value to a public, instance, writable property in the destination.
///
/// The type of the source.
/// The source.
/// The target.
/// The ignore properties.
///
/// Number of properties that was copied successful.
///
public static Int32 CopyPropertiesTo(this T source, Object? target, params String[]? ignoreProperties) where T : class => ObjectMapper.Copy(source, target, GetCopyableProperties(target), ignoreProperties);
///
/// Copies the properties to new instance of T.
///
/// The new object type.
/// The source.
/// The ignore properties.
///
/// The specified type with properties copied.
///
/// source.
public static T CopyPropertiesToNew(this Object source, String[]? ignoreProperties = null) where T : class {
if(source == null) {
throw new ArgumentNullException(nameof(source));
}
T target = Activator.CreateInstance();
_ = ObjectMapper.Copy(source, target, GetCopyableProperties(target), ignoreProperties);
return target;
}
///
/// Gets the copyable properties.
///
/// If there is no properties with the attribute AttributeCache returns all the properties.
///
/// The object.
///
/// Array of properties.
///
/// model.
///
public static IEnumerable GetCopyableProperties(this Object? @this) {
if(@this == null) {
throw new ArgumentNullException(nameof(@this));
}
global::System.Collections.Generic.IEnumerable collection = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(@this.GetType(), true);
global::System.Collections.Generic.IEnumerable properties = collection.Select(x => new {
x.Name,
HasAttribute = AttributeCache.DefaultCache.Value.RetrieveOne(x) != null,
}).Where(x => x.HasAttribute).Select(x => x.Name);
return properties.Any() ? properties : collection.Select(x => x.Name);
}
internal static void CreateTarget(this Object source, Type targetType, Boolean includeNonPublic, ref Object? target) {
switch(source) {
// do nothing. Simply skip creation
case String _:
break;
// When using arrays, there is no default constructor, attempt to build a compatible array
case IList sourceObjectList when targetType.IsArray:
Type? elementType = targetType.GetElementType();
if(elementType != null) {
target = Array.CreateInstance(elementType, sourceObjectList.Count);
}
break;
default:
IEnumerable> constructors = ConstructorTypeCache.DefaultCache.Value.RetrieveAllConstructors(targetType, includeNonPublic);
// Try to check if empty constructor is available
if(constructors.Any(x => x.Item2.Length == 0)) {
target = Activator.CreateInstance(targetType, includeNonPublic);
} else {
Tuple firstCtor = constructors.OrderBy(x => x.Item2.Length).FirstOrDefault();
target = Activator.CreateInstance(targetType, firstCtor?.Item2.Select(arg => arg.GetType().GetDefault()).ToArray());
}
break;
}
}
internal static String GetNameWithCase(this String name, JsonSerializerCase jsonSerializerCase) => jsonSerializerCase switch
{
JsonSerializerCase.PascalCase => Char.ToUpperInvariant(name[0]) + name.Substring(1),
JsonSerializerCase.CamelCase => Char.ToLowerInvariant(name[0]) + name.Substring(1),
JsonSerializerCase.None => name,
_ => throw new ArgumentOutOfRangeException(nameof(jsonSerializerCase), jsonSerializerCase, null)
};
}
}