2017-11-23 03:23:43 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using NLog;
|
2017-11-23 13:49:48 +01:00
|
|
|
|
using WatchFace.Parser.Models;
|
2017-11-23 03:23:43 +01:00
|
|
|
|
|
2017-11-23 13:49:48 +01:00
|
|
|
|
namespace WatchFace.Parser.Utils
|
2017-11-23 03:23:43 +01:00
|
|
|
|
{
|
|
|
|
|
public class ParametersConverter
|
|
|
|
|
{
|
|
|
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
|
|
2017-11-25 01:30:43 +01:00
|
|
|
|
public static List<Parameter> Build<T>(T serializable, string path = "")
|
2017-11-23 03:23:43 +01:00
|
|
|
|
{
|
|
|
|
|
var result = new List<Parameter>();
|
2017-11-25 01:30:43 +01:00
|
|
|
|
var currentType = typeof(T);
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(path))
|
|
|
|
|
Logger.Trace("{0} '{1}'", path, currentType.Name);
|
2017-11-26 20:24:47 +01:00
|
|
|
|
foreach (var kv in ElementsHelper.SortedProperties<T>())
|
2017-11-23 03:23:43 +01:00
|
|
|
|
{
|
|
|
|
|
var id = kv.Key;
|
2017-11-25 01:30:43 +01:00
|
|
|
|
var currentPath = string.IsNullOrEmpty(path)
|
|
|
|
|
? id.ToString()
|
|
|
|
|
: string.Concat(path, '.', id.ToString());
|
|
|
|
|
|
2017-11-23 03:23:43 +01:00
|
|
|
|
var propertyInfo = kv.Value;
|
|
|
|
|
var propertyType = propertyInfo.PropertyType;
|
|
|
|
|
dynamic propertyValue = propertyInfo.GetValue(serializable, null);
|
|
|
|
|
|
2017-11-25 01:30:43 +01:00
|
|
|
|
if (propertyValue == null)
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-12-09 13:36:15 +01:00
|
|
|
|
if (propertyType == typeof(long) ||
|
|
|
|
|
propertyType == typeof(TextAlignment) ||
|
|
|
|
|
propertyType == typeof(bool))
|
2017-11-25 01:30:43 +01:00
|
|
|
|
{
|
2017-12-09 13:36:15 +01:00
|
|
|
|
long value;
|
|
|
|
|
if (propertyType == typeof(bool))
|
|
|
|
|
value = propertyValue ? 1 : 0;
|
|
|
|
|
else
|
|
|
|
|
value = (long) propertyValue;
|
|
|
|
|
|
|
|
|
|
Logger.Trace("{0} '{1}': {2}", currentPath, propertyInfo.Name, value);
|
|
|
|
|
result.Add(new Parameter(id, value));
|
2017-11-25 01:30:43 +01:00
|
|
|
|
}
|
2017-11-25 22:02:33 +01:00
|
|
|
|
else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
|
|
|
{
|
|
|
|
|
Logger.Trace("{0} '{1}': {2}", currentPath, propertyInfo.Name, propertyValue);
|
|
|
|
|
result.Add(new Parameter(id, propertyValue));
|
|
|
|
|
}
|
2017-11-23 03:23:43 +01:00
|
|
|
|
else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
|
2017-11-25 01:30:43 +01:00
|
|
|
|
{
|
|
|
|
|
foreach (var item in propertyValue)
|
|
|
|
|
result.Add(new Parameter(id, Build(item, currentPath)));
|
|
|
|
|
}
|
2017-11-23 03:23:43 +01:00
|
|
|
|
else
|
2017-11-25 01:30:43 +01:00
|
|
|
|
{
|
2018-04-30 23:54:51 +02:00
|
|
|
|
var innerParameters = Build(propertyValue, currentPath);
|
|
|
|
|
if (innerParameters.Count > 0)
|
|
|
|
|
result.Add(new Parameter(id, innerParameters));
|
|
|
|
|
else
|
|
|
|
|
Logger.Trace("{0} '{1}': Skipped because of empty", currentPath, propertyInfo.Name);
|
2017-11-25 01:30:43 +01:00
|
|
|
|
}
|
2017-11-23 03:23:43 +01:00
|
|
|
|
}
|
2017-12-09 13:36:15 +01:00
|
|
|
|
|
2017-11-23 03:23:43 +01:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 01:30:43 +01:00
|
|
|
|
public static T Parse<T>(List<Parameter> descriptor, string path = "") where T : new()
|
2017-11-23 03:23:43 +01:00
|
|
|
|
{
|
2017-11-26 20:24:47 +01:00
|
|
|
|
var properties = ElementsHelper.SortedProperties<T>();
|
2017-11-23 03:23:43 +01:00
|
|
|
|
var result = new T();
|
2017-11-25 00:03:47 +01:00
|
|
|
|
var currentType = typeof(T);
|
|
|
|
|
|
2017-11-25 01:30:43 +01:00
|
|
|
|
var thisMethod = typeof(ParametersConverter).GetMethod(nameof(Parse));
|
|
|
|
|
|
2017-11-25 00:03:47 +01:00
|
|
|
|
if (!string.IsNullOrEmpty(path))
|
|
|
|
|
Logger.Trace("{0} '{1}'", path, currentType.Name);
|
2017-11-23 03:23:43 +01:00
|
|
|
|
foreach (var parameter in descriptor)
|
|
|
|
|
{
|
2017-11-25 00:03:47 +01:00
|
|
|
|
var currentPath = string.IsNullOrEmpty(path)
|
|
|
|
|
? parameter.Id.ToString()
|
|
|
|
|
: string.Concat(path, '.', parameter.Id.ToString());
|
|
|
|
|
if (!properties.ContainsKey(parameter.Id))
|
|
|
|
|
throw new ArgumentException($"Parameter {parameter.Id} isn't supported for {currentType.Name}");
|
2017-11-23 03:23:43 +01:00
|
|
|
|
|
2017-11-25 00:03:47 +01:00
|
|
|
|
var propertyInfo = properties[parameter.Id];
|
2017-11-23 03:23:43 +01:00
|
|
|
|
var propertyType = propertyInfo.PropertyType;
|
|
|
|
|
|
2017-12-09 13:36:15 +01:00
|
|
|
|
if (propertyType == typeof(long) ||
|
|
|
|
|
propertyType == typeof(TextAlignment) ||
|
|
|
|
|
propertyType == typeof(bool) ||
|
|
|
|
|
propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
2017-11-23 03:23:43 +01:00
|
|
|
|
{
|
2017-11-25 00:03:47 +01:00
|
|
|
|
Logger.Trace("{0} '{1}': {2}", currentPath, propertyInfo.Name, parameter.Value);
|
2017-11-26 20:24:47 +01:00
|
|
|
|
dynamic propertyValue = propertyInfo.GetValue(result, null);
|
2017-11-25 22:02:33 +01:00
|
|
|
|
|
|
|
|
|
if (propertyType.IsGenericType && propertyValue != null)
|
|
|
|
|
throw new ArgumentException($"Parameter {parameter.Id} is already set for {currentType.Name}");
|
|
|
|
|
|
2017-12-09 13:36:15 +01:00
|
|
|
|
if (!propertyType.IsGenericType && propertyType == typeof(long) && propertyValue != 0)
|
2017-11-25 00:03:47 +01:00
|
|
|
|
throw new ArgumentException($"Parameter {parameter.Id} is already set for {currentType.Name}");
|
2017-11-23 14:48:47 +01:00
|
|
|
|
|
2017-12-09 13:36:15 +01:00
|
|
|
|
if (propertyType == typeof(TextAlignment))
|
|
|
|
|
propertyInfo.SetValue(result, (TextAlignment) parameter.Value, null);
|
|
|
|
|
else if (propertyType == typeof(bool))
|
|
|
|
|
propertyInfo.SetValue(result, parameter.Value > 0, null);
|
|
|
|
|
else
|
|
|
|
|
propertyInfo.SetValue(result, parameter.Value, null);
|
2017-11-23 03:23:43 +01:00
|
|
|
|
}
|
|
|
|
|
else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
|
|
|
|
|
{
|
2017-11-26 20:24:47 +01:00
|
|
|
|
dynamic propertyValue = propertyInfo.GetValue(result, null);
|
2017-11-23 03:23:43 +01:00
|
|
|
|
if (propertyValue == null)
|
|
|
|
|
{
|
|
|
|
|
propertyValue = Activator.CreateInstance(propertyType);
|
2017-11-26 20:24:47 +01:00
|
|
|
|
propertyInfo.SetValue(result, propertyValue, null);
|
2017-11-23 03:23:43 +01:00
|
|
|
|
}
|
2017-11-23 14:48:47 +01:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-11-25 01:30:43 +01:00
|
|
|
|
var generic = thisMethod.MakeGenericMethod(propertyType.GetGenericArguments()[0]);
|
2017-11-25 00:03:47 +01:00
|
|
|
|
dynamic parsedValue = generic.Invoke(null,
|
2017-11-25 01:30:43 +01:00
|
|
|
|
new dynamic[] {parameter.Children, currentPath});
|
2017-11-23 14:48:47 +01:00
|
|
|
|
propertyValue.Add(parsedValue);
|
|
|
|
|
}
|
|
|
|
|
catch (TargetInvocationException e)
|
|
|
|
|
{
|
|
|
|
|
throw e.InnerException;
|
|
|
|
|
}
|
2017-11-23 03:23:43 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-11-26 20:24:47 +01:00
|
|
|
|
dynamic propertyValue = propertyInfo.GetValue(result, null);
|
2017-11-23 14:48:47 +01:00
|
|
|
|
if (propertyValue != null)
|
2017-11-25 00:03:47 +01:00
|
|
|
|
throw new ArgumentException($"Parameter {parameter.Id} is already set for {currentType.Name}");
|
2017-11-23 14:48:47 +01:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-11-25 01:30:43 +01:00
|
|
|
|
var generic = thisMethod.MakeGenericMethod(propertyType);
|
|
|
|
|
dynamic parsedValue = generic.Invoke(null, new object[] {parameter.Children, currentPath});
|
2017-11-26 20:24:47 +01:00
|
|
|
|
propertyInfo.SetValue(result, parsedValue, null);
|
2017-11-23 14:48:47 +01:00
|
|
|
|
}
|
|
|
|
|
catch (TargetInvocationException e)
|
|
|
|
|
{
|
|
|
|
|
throw e.InnerException;
|
|
|
|
|
}
|
2017-11-23 03:23:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-09 13:36:15 +01:00
|
|
|
|
|
2017-11-23 03:23:43 +01:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|