using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FLY.Modbus
{
    /// <summary>
    /// 数据映射的类;
    /// Data: PC 属性 
    /// Regs: PLC 对象（寄存器、线圈）
    /// </summary>
    public class DataToRegs
    {
        /// <summary>
        /// 所属的plc
        /// </summary>
        public ModbusMapper mapper;

        /// <summary>
        /// 对应 PLC寄存器区 coil or register
        /// </summary>
        public PLCAddressArea dataArea;

        /// <summary>
        /// PLC 首地址
        /// </summary>
        public int addr;

        /// <summary>
        /// PLC 尾地址
        /// </summary>
        public int endAddr;

        /// <summary>
        /// value 的C#类型 float,int16,int32
        /// </summary>
        public REG_TYPE type;

        /// <summary>
        /// 放大倍数， value * scale 才是属性的值
        /// </summary>
        public double scale;

        /// <summary>
        /// object 
        /// </summary>
        public object owner;

        /// <summary>
        /// object 的 property 名称， 只能是 数字类型都是double， 剩下就是 bool
        /// </summary>
        public string propertyName;

        /// <summary>
        /// property 的值, 没有缩小. 只有 double 与 bool 
        /// </summary>
        public object value;

        /// <summary>
        /// PLC obj ,bool or UInt16[]
        /// </summary> 
        public object plcValue;

        /// <summary>
        /// PLC obj 寄存器值是否改变
        /// </summary>
        public bool isPlcValueChanged;

        /// <summary>
        /// 需要从PLC读取数据更新
        /// </summary>
        public bool isNeedUpdate = false;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mapper"></param>
        /// <param name="dataArea"></param>
        /// <param name="addr"></param>
        /// <param name="type"></param>
        /// <param name="scale"></param>
        /// <param name="owner"></param>
        /// <param name="propertyname"></param>
        public DataToRegs(ModbusMapper mapper, PLCAddressArea dataArea, int addr, REG_TYPE type, double scale, object owner, string propertyname)
        {
            this.mapper = mapper;
            this.dataArea = dataArea;
            this.addr = addr;
            this.type = type;
            this.scale = scale;
            this.owner = owner;
            this.propertyName = string.Copy(propertyname);

            if (type == REG_TYPE.BOOL)
            {
                plcValue = false;
                endAddr = addr;
            }
            else
            {
                plcValue = new UInt16[ModbusMapper.RegSize(type)];
                endAddr = addr + ((UInt16[])plcValue).Count() - 1;
            }
        }

        /// <summary>
        /// PLC 对象（寄存器、线圈）转 PC 属性
        /// </summary>
        /// <param name="plc_value">bool or UInt16[]</param>
        /// <returns></returns>
        public object ToPropertyObj(object plc_value)
        {
            if (type == REG_TYPE.BOOL)
            {
                return plc_value;
            }
            else
            {
                return RegTypeConverter.ToObject((UInt16[])plc_value, type, scale);
            }
        }
        /// <summary>
        /// PLC 对象（寄存器、线圈）转 PC 属性, 本地
        /// </summary>
        public void ToPropertyObj()
        {
            value = ToPropertyObj(plcValue);
        }

        /// <summary>
        /// PC 属性 转 PLC 对象（寄存器、线圈）
        /// </summary>
        /// <param name="value"></param>
        /// <returns>bool or UInt16[]</returns>
        public object ToPLCObj(object value)
        {
            if (type == REG_TYPE.BOOL)
                return value;
            else
                return RegTypeConverter.ToRegs(value, type, scale);
        }
        /// <summary>
        /// PC 属性 转 PLC 对象（寄存器、线圈）, 本地
        /// </summary>
        public void ToPLCObj()
        {
            object plcobj = ToPLCObj(value);

            //更新 本地的 PLC 数据
            switch (dataArea)
            {
                case PLCAddressArea.Coil:
                    plcValue = plcobj;
                    break;
                case PLCAddressArea.Register:
                    {
                        UInt16[] src = plcobj as UInt16[];
                        UInt16[] dest = plcValue as UInt16[];
                        Array.Copy(src, dest, dest.Length);
                    }
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return propertyName + " [" + ((int)dataArea).ToString() + "](" + addr + ")";
        }
    }
}
