using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Quadarax.Foundation.Common.Reflection
{
    public static class TypePropertyLocator
    {
        private static readonly IDictionary<string, PropertyInfo> _propertyCache = new Dictionary<string, PropertyInfo>();


        public static PropertyInfo GetProperty(this Type type, string propertyName)
        {
            var key = GetCacheKey(type, propertyName);
            if (_propertyCache.ContainsKey(key))
                return _propertyCache[key];
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.IgnoreCase);
            var property = properties.SingleOrDefault(x => x.Name == propertyName);
            if (property!=null)
                _propertyCache.Add(key,property);
            return property;
        }

        public static object GetPropertyValue(this Type type, string propertyName, object sourceObject)
        {
            if (sourceObject==null)
                throw new ArgumentNullException(nameof(sourceObject));
            var property = type.GetProperty(propertyName);
            if (property == null)
                throw new ArgumentException($"Property '{propertyName}' doesn't exists in type '{type.Name}'.", nameof(propertyName));
            return property.GetValue(sourceObject);
        }

        public static string GetPropertyValueAsString(this Type type, string propertyName, object sourceObject)
        {
            var value = type.GetPropertyValue(propertyName, sourceObject);
            return value != null? value.ToString() : string.Empty;
        }

        private static string GetCacheKey(Type type, string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
                throw new ArgumentNullException(nameof(propertyName));
            return type.FullName + "_" + propertyName;
        }
    }
}
