namespace Unosquare.Swan.Components
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Abstractions;
///
/// Represents an object map.
///
/// The type of the source.
/// The type of the destination.
///
public class ObjectMap : IObjectMap
{
internal ObjectMap(IEnumerable intersect)
{
SourceType = typeof(TSource);
DestinationType = typeof(TDestination);
Map = intersect.ToDictionary(
property => DestinationType.GetProperty(property.Name),
property => new List {SourceType.GetProperty(property.Name)});
}
///
public Dictionary> Map { get; }
///
public Type SourceType { get; }
///
public Type DestinationType { get; }
///
/// Maps the property.
///
/// The type of the destination property.
/// The type of the source property.
/// The destination property.
/// The source property.
///
/// An object map representation of type of the destination property
/// and type of the source property.
///
public ObjectMap MapProperty
(
Expression> destinationProperty,
Expression> sourceProperty)
{
var propertyDestinationInfo = (destinationProperty.Body as MemberExpression)?.Member as PropertyInfo;
if (propertyDestinationInfo == null)
{
throw new ArgumentException("Invalid destination expression", nameof(destinationProperty));
}
var sourceMembers = GetSourceMembers(sourceProperty);
if (sourceMembers.Any() == false)
{
throw new ArgumentException("Invalid source expression", nameof(sourceProperty));
}
// reverse order
sourceMembers.Reverse();
Map[propertyDestinationInfo] = sourceMembers;
return this;
}
///
/// Removes the map property.
///
/// The type of the destination property.
/// The destination property.
///
/// An object map representation of type of the destination property
/// and type of the source property.
///
/// Invalid destination expression.
public ObjectMap RemoveMapProperty(
Expression> destinationProperty)
{
var propertyDestinationInfo = (destinationProperty.Body as MemberExpression)?.Member as PropertyInfo;
if (propertyDestinationInfo == null)
throw new ArgumentException("Invalid destination expression", nameof(destinationProperty));
if (Map.ContainsKey(propertyDestinationInfo))
{
Map.Remove(propertyDestinationInfo);
}
return this;
}
private static List GetSourceMembers(Expression> sourceProperty)
{
var sourceMembers = new List();
var initialExpression = sourceProperty.Body as MemberExpression;
while (true)
{
var propertySourceInfo = initialExpression?.Member as PropertyInfo;
if (propertySourceInfo == null) break;
sourceMembers.Add(propertySourceInfo);
initialExpression = initialExpression.Expression as MemberExpression;
}
return sourceMembers;
}
}
}