﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Reflection;
using Arch.CFramework.Utility;

namespace Arch.CFramework.AppInternals.Components
{
    /// <summary>
    /// Component基类，所有的Component都继承这个基类
    /// </summary>
    public abstract class ComponentBase : IComponent
    {
        /// <summary>
        /// 属性集合
        /// </summary>
        ConcurrentDictionary<string, PropertyInfo> properties = new ConcurrentDictionary<string, PropertyInfo>();
        /// <summary>
        /// PropertyName结合
        /// </summary>
        IEnumerable<PropertyName> propertyNameCollection = null;

        /// <summary>
        /// 虚泛型方法，得到属性值 希望子类重写
        /// </summary>
        /// <typeparam name="TValue">值</typeparam>
        /// <param name="propertyName">属性名</param>
        /// <returns>属性值</returns>
        public virtual TValue Get<TValue>(string propertyName)
        {
            TValue defaultVal = default(TValue);
            object obj = Get(propertyName);
            if (obj != null)
            {
                defaultVal = (TValue)obj;
            }
            return defaultVal;
        }

        /// <summary>
        /// 反射得到属性值
        /// </summary>
        /// <param name="propertyName">属性名</param>
        /// <returns>属性值</returns>
        public object Get(string propertyName)
        {
            object obj = null;
            PropertyInfo property = GetPropertyInfo(propertyName);
            if (property != null && property.CanRead)
            {
                obj = property.GetValue(this, null);
            }
            return obj;
        }

        /// <summary>
        /// 反射 根据属性名得到属性信息
        /// </summary>
        /// <param name="propertyName">属性名</param>
        /// <returns>属性信息</returns>
        protected PropertyInfo GetPropertyInfo(string propertyName)
        {
            PropertyInfo property = null;
            if (!properties.TryGetValue(propertyName, out property))
            {
                property = this.GetType().GetProperty(propertyName);
                properties.TryAdd(propertyName, property);
            }
            return property;
        }

        /// <summary>
        /// 虚方法 得到所有PropertyName
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<PropertyName> GetPropertyNames()
        {
            if (propertyNameCollection == null)
            {
                propertyNameCollection = this.GetType()
                            .GetProperties()
                            .Select(a => new PropertyName() { Name = a.Name, CanWrite = a.CanWrite, CanRead = a.CanRead, PropertyType = a.PropertyType })
                            .OfType<PropertyName>();
            }
            return propertyNameCollection;
        }


        /// <summary>
        /// 根据序列化器读
        /// </summary>
        /// <param name="serializer">序列化器</param>
        /// <returns></returns>
        public virtual string Read(Serialization.ISerializer serializer)
        {
            Guard.ArgumentNotNull(serializer, "serializer");
            return serializer.Serializer(this, Encoding.UTF8);
        }
    }
}
