using PlcSiemens.O;
using PlcSiemens.Protocol.Common;
using PlcSiemens.Protocol.ReadData;
using PlcSiemens.Protocol.WriteData;

namespace PlcSiemens.ProtocolHandle
{
    public class WriteHandle : IPacketHandle
    {
        public ushort PduLength { get; set; }
        public DataItem DataItem { get; set; }
        public ResultCode ResultCode { get; private set; }

        public void Handle(IIsoSender sender)
        {
            if (DataItem.Db > 65535 || DataItem.Length < 1)
                throw new ArgumentException("参数异常");
            if (DataItem.DataType == DataType.Bit && DataItem.Length > 1)
                throw new ArgumentException("Bit只能写一位");

            const int rhSize = 10 +    // Request header
                               2 +                       // FunWrite+ItemCount (of TReqFunWriteParams)
                               12 +// 1 item reference
                               4; // ReturnCode+TransportSize+DataLength

            var sizeByte = DataItem.SizeByte;
            var maxCount = (ushort)((PduLength - rhSize) / sizeByte);
            var totalCount = DataItem.Length;
            var offset = DataItem.Start;

            DataItem currentItem = new DataItem()
            {
                AreaType = DataItem.AreaType,
                DataType = DataItem.DataType,
                Db = DataItem.Db,
                Start = DataItem.Start,
                Data = DataItem.Data,
                Length = 0,
                DataOffset = 0
            };

            while (totalCount > 0)
            {
                var curCount = totalCount;
                if (curCount > maxCount)
                    curCount = maxCount;

                currentItem.Start = offset;
                currentItem.Length = curCount;
                WriteRequest write = new WriteRequest();
                write.DataItems = new List<DataItem>() { currentItem };

                WriteResponse res = sender.IsoSend<WriteRequest, WriteResponse>(write);

                if (res.Header.Error == 0x0000)
                {
                    var size = (ushort)(currentItem.SizeByte * curCount);
                    offset += size;
                    currentItem.DataOffset += size;
                    totalCount -= curCount;
                }
                else
                    break;
            }

            ResultCode = ResultCode.OKFF;
        }
    }
}
