using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MES.Utility.Network.S7netplus.ORM
{
    public class S7Read<T> where T : class, new()
    {
        private S7Client opcClient;
        private Dictionary<string, PropertyInfo> fieldDict;
        private Dictionary<string, int> stringLengthDict;
        /// <summary>
        /// 构造方法，传入参数
        /// </summary>
        /// <param name="opcClient"></param>
        public S7Read(S7Client opcClient)
        {
            this.opcClient = opcClient;
            //默认取出所有的只读或者可读可写的属性
            GetNodeType(out fieldDict, out stringLengthDict);
        }

        /// <summary>
        /// 获得所有具有可读属性的数据
        /// </summary>
        /// <returns></returns>
        private void GetNodeType(out Dictionary<string, PropertyInfo> fieldDict, out Dictionary<string, int> stringLengthDict)
        {
            fieldDict = new Dictionary<string, PropertyInfo>();
            stringLengthDict = new Dictionary<string, int>();

            //获得对象T的属性
            PropertyInfo[] properties = typeof(T).GetProperties();
            //得到所有添加注解的属性
            foreach (PropertyInfo info in properties)
            {
                //判断是否具有HttpController属性
                Object[] attr = info.GetCustomAttributes(false);
                if (attr.Length == 0)
                {
                    continue;
                }
                //从注解数组中取第一个注解(一个属性可以包含多个注解)
                S7PLCAttribute myattr = attr[0] as S7PLCAttribute;
                if (myattr == null)
                    continue;
                if (myattr.Type == S7NodeType.ReadAndWrite || myattr.Type == S7NodeType.ReadOnly)
                {
                    fieldDict.Add(myattr.Address, info);
                    stringLengthDict.Add(myattr.Address, myattr.StrLength);
                }
            }
        }

        /// <summary>
        /// 执行获得数据，映射成对象
        /// </summary>
        /// <param name="message">返回错误信息</param>
        /// <returns></returns>
        public bool Execute(out T t)
        {

            if (fieldDict.Count == 0)
            {
                t = default(T);
                return false;
            }
            try
            {
                if (!opcClient.IsConnected)
                {
                    t = default(T);
                    return false;
                }
                bool flag = false;
                T entity = (T)Activator.CreateInstance(typeof(T));
                //循环读取每一个
                foreach (KeyValuePair<string, PropertyInfo> keyValue in fieldDict)
                {
                    //判断当前keyValue是什么类型
                    if (keyValue.Value.PropertyType == typeof(ushort))
                    {
                        ushort value=0;
                        flag = opcClient.Plc.ReadInt16(keyValue.Key, out value);
                        if (!flag)
                        {
                            t = default(T);
                            return false;
                        }
                        keyValue.Value.SetValue(entity, value);
                    }
                    else if (keyValue.Value.PropertyType == typeof(int))
                    {
                        ushort value =0;
                        flag = opcClient.Plc.ReadInt16(keyValue.Key, out value);
                        if (!flag)
                        {
                            t = default(T);
                            return false;
                        }
                        keyValue.Value.SetValue(entity, value);
                    }
                    //else if (keyValue.Value.PropertyType == typeof(float))
                    //{
                    //    float value;
                    //    flag = opcClient.Plc.ReadReal(keyValue.Key, out value);
                    //    if (!flag)
                    //    {
                    //        t = default(T);
                    //        return false;
                    //    }
                    //    keyValue.Value.SetValue(entity, value);
                    //}
                    else if (keyValue.Value.PropertyType == typeof(string))
                    {
                        string value;
                        flag = opcClient.Plc.ReadString(keyValue.Key, stringLengthDict[keyValue.Key], out value);
                        if (!flag)
                        {
                            t = default(T);
                            return false;
                        }
                        keyValue.Value.SetValue(entity, value);
                    }
                }
                t = entity;
                return true;
            }
            catch
            {
                t = default(T);
                return false;
            }
        }


        /// <summary>
        /// 传入Lambda表达式，指定读取的数据
        /// </summary>
        /// <param name="columns"></param>
        /// <returns></returns>
        public S7Read<T> ReadField(Expression<Func<T, object>> columns)
        {
            Dictionary<string, PropertyInfo> fieldDict = new Dictionary<string, PropertyInfo>();
            Dictionary<string, int> stringLengthDict = new Dictionary<string, int>();

            //取出要读的属性
            string lambda = columns.Body.ToString();
            int index1 = lambda.IndexOf('(');
            int index2 = lambda.IndexOf(')');
            string str = lambda.Substring(index1 + 1, index2 - index1 - 1);
            List<string> keyList = str.Split(',').Select(it => it.Split('=')[0].Trim()).ToList();
            fieldDict.Clear();
            //获得对象T的属性
            PropertyInfo[] properties = typeof(T).GetProperties();
            //得到所有添加注解的属性
            foreach (PropertyInfo info in properties)
            {
                //判断是否具有HttpController属性
                Object[] attr = info.GetCustomAttributes(false);
                if (attr.Length == 0)
                {
                    continue;
                }
                //从注解数组中取第一个注解(一个属性可以包含多个注解)
                S7PLCAttribute myattr = attr[0] as S7PLCAttribute;
                if (myattr == null)
                    continue;
                if (myattr.Type == S7NodeType.ReadAndWrite || myattr.Type == S7NodeType.ReadOnly)
                {
                    if (keyList.Contains(info.Name))
                    {
                        fieldDict.Add(myattr.Address, info);
                        stringLengthDict.Add(myattr.Address, myattr.StrLength);
                    }
                }
            }
            this.fieldDict = fieldDict;
            this.stringLengthDict = stringLengthDict;
            return this;
        }
    }
}
