using FLY.Thick.Base.IService;
using FObjBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace FLY.Thick.Base.Common
{
    /// <summary>
    /// AD盒IO定义，避免忘记IO口的定义，出现功能重复
    /// 
    /// 使用方法：
    /// 1.每款机型例如吹膜 继承FlyADIODefine
    /// 2.添加 输入口，输出口
    /// 3.重载 GetInputPropertyNames 显示输出 输入口定义
    /// 4.重载 GetOutputPropertyNames 显示输出 输出口定义
    /// 5.重定义 static new FlyADIODefine Instance
    /// 
    /// 6.在Gage中 调用 FlyADIODefine.SetInstance(new FlyADIODefine());
    /// 7.在Gage中 注册 AD盒事件， AD盒版本修改时，FlyADIODefine.SerVersion(version);
    /// </summary>
    public class FlyADIODefine: IFlyAdIoDefineService
    {
        protected static FlyADIODefine instance;
        public static void SetInstance(FlyADIODefine flyADIODefine) 
        {
            instance = flyADIODefine;
        }
        /// <summary>
        /// 子类 需要 重新 把子类对象 赋值给 Instance, 确保整个环境只用一个版本的 单例
        /// </summary>
        public static FlyADIODefine Instance => instance;
        
        #region 输入口
        /// <summary>
        /// 归零信号
        /// </summary>
        [Description("归零信号")]
        public int InNo_Org { get; protected set; } = 2 - 1;

        /// <summary>
        /// 正向限位
        /// </summary>
        [Description("正向限位")]
        public int InNo_Limit_Forw { get; protected set; } = 3 - 1;
        /// <summary>
        /// 反向限位
        /// </summary>
        [Description("反向限位")]
        public int InNo_Limit_Backw { get; protected set; } = 4 - 1;

        /// <summary>
        /// 数据有效
        /// </summary>
        [Description("数据有效")]
        public int InNo_DataValid { get; protected set; } = 6 - 1;

        /// <summary>
        /// 急停 and 手动正转
        /// </summary>
        [Description("急停 & 手动正转")]
        public int InNo_Manual_Forw { get; protected set; } = 7 - 1;

        /// <summary>
        /// 急停 and 手动反转
        /// </summary>
        [Description("急停 & 手动反转")]
        public int InNo_Manual_Backw { get; protected set; } = 8 - 1;

        /// <summary>
        /// 同步输入信号
        /// </summary>
        [Description("同步输入信号")]
        public int InNo_Sync { get; protected set; } = 9 - 1;

        /// <summary>
        /// 辊速信号
        /// </summary>
        [Description("辊速信号")]
        public int InNo_Roll { get; protected set; } = 11 - 1;

        /// <summary>
        /// 控制主轴脉冲启动计数输入， o3 接 i11;
        /// i11 为 0 计数停止
        /// </summary>
        [Description("主轴脉冲启动计数")]
        public int InNo_Pos2OnOff { get; protected set; } = 11 - 1;

        /// <summary>
        /// 纵向光纤信号
        /// </summary>
        [Description("纵向光纤信号")]
        public int InNo_VSign { get; protected set; } = 12 - 1;

        #endregion
        #region 输出口
        /// <summary>
        /// 变频器反转 VF0 是松下的变频器牌子
        /// </summary>
        [Description("变频器反转")]
        public int OutNo_VF0_Backw { get; protected set; } = 1 - 1;
        /// <summary>
        /// 变频器正转 VF0 是松下的变频器牌子
        /// </summary>
        [Description("变频器正转")]
        public int OutNo_VF0_Forw { get; protected set; } = 2 - 1;
        /// <summary>
        /// 变频器减速 VF0 是松下的变频器牌子
        /// </summary>
        [Description("变频器减速")]
        public int OutNo_VF0_Slow { get; protected set; } = 3 - 1;

        /// <summary>
        /// 控制主轴脉冲启动计数
        /// </summary>
        [Description("主轴脉冲启动计数")]
        public int OutNo_Pos2OnOff { get; protected set; } = 3 - 1;

        /// <summary>
        /// 同步输出信号
        /// </summary>
        [Description("同步输出信号")]
        public int OutNo_Sync { get; protected set; } = 3 - 1;

        /// <summary>
        /// 报警信号
        /// </summary>
        [Description("报警信号")]
        public int OutNo_Alarm { get; protected set; } = 4 - 1;


        #endregion

        private int version = 2;
        /// <summary>
        /// 根据AD盒的版本，设置
        /// </summary>
        /// <param name="version"></param>
        public virtual void SerVersion(int version)
        {
            this.version = version;
            if (this.version == 3)
            {
                InNo_Org = 13 - 1;
                InNo_Limit_Forw = 14 - 1;
                InNo_Limit_Backw = 16 - 1;

                InNo_Roll = 15 - 1;
            }
            else
            {
                InNo_Org = 2 - 1;
                InNo_Limit_Forw = 3 - 1;
                InNo_Limit_Backw = 4 - 1;

                InNo_Roll = 11 - 1;
            }
        }

        /// <summary>
        /// 获取输入口 属性名
        /// </summary>
        /// <returns></returns>
        protected virtual List<string> GetInputPropertyNames() 
        {
            List<string> reponse = new List<string>();
            Type t = this.GetType();
            var properties = t.GetProperties();

            foreach (var property in properties)
            {
                if (property.Name.StartsWith("InNo_"))
                {
                    //输入
                    reponse.Add(property.Name);
                }
            }
            return reponse;
        }
        /// <summary>
        /// 获取输出口 属性名
        /// </summary>
        /// <returns></returns>
        protected virtual List<string> GetOutputPropertyNames()
        {
            List<string> reponse = new List<string>();
            Type t = this.GetType();
            var properties = t.GetProperties();

            foreach (var property in properties)
            {
                if (property.Name.StartsWith("OutNo_"))
                {
                    //输入
                    reponse.Add(property.Name);
                }
            }
            return reponse;
        }
        public void GetIODefine(AsyncCBHandler asyncDelegate, object asyncContext)
        {
            //获取全部带 Description 的属性，且名字 InNo_XXX 或 OutNo_XXX
            IODefineCollection reponse = new IODefineCollection();
            
            List<IODefine> list = new List<IODefine>();
            reponse.List = list;
            if (version == 3)
            {
                reponse.InCount = 16;
                reponse.OutCount = 8;
            }
            else {
                reponse.InCount = 12;
                reponse.OutCount = 4;
            }

            var inputPropertyNames = GetInputPropertyNames();
            var outputPropertyNames = GetOutputPropertyNames();

            Type t = this.GetType();
            
            foreach (var propertyName in inputPropertyNames)
            {
                var property = t.GetProperty(propertyName);
               
                var attrs = property.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Count() == 0)
                {
                    throw new Exception($"{propertyName} 没有写 [Description]");
                }

                var attr = attrs.First() as DescriptionAttribute;
                string desp = attr.Description;

                var index = (int)property.GetValue(this);
                var iodefine = new IODefine()
                {
                    IoType = IODefine.IOTYPE.Input,
                    Index = index,
                    Description = desp
                };
                list.Add(iodefine);
            }

            foreach (var propertyName in outputPropertyNames)
            {
                var property = t.GetProperty(propertyName);

                var attrs = property.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs.Count() == 0)
                {
                    throw new Exception($"{propertyName} 没有写 [Description]");
                }

                var attr = attrs.First() as DescriptionAttribute;
                string desp = attr.Description;

                var index = (int)property.GetValue(this);
                var iodefine = new IODefine()
                {
                    IoType = IODefine.IOTYPE.Output,
                    Index = index,
                    Description = desp
                };
                list.Add(iodefine);
            }

            asyncDelegate?.Invoke(asyncContext, reponse);
        }
    }
}
