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

namespace iSTP_Embedded
{
    /// <summary>
    /// Represents memory of all messages whos need ack to response.
    /// </summary>
    public class ACK
    {
        #region --------------------------- Private global values ---------------------------
        private List<EmbeddedPacket> MsgMemmory;
        private DateTime LastMSG;
        private TimeSpan WaitingTime = TimeSpan.FromSeconds(5);
        #endregion

        #region --------------------------- Public global values ---------------------------
        public int GetNumACK4return { get { return (MsgMemmory == null)? 0 : MsgMemmory.Count; } }
        public TimeSpan GetWaitingTime { get { return WaitingTime; } }
        public DateTime GetLastMSGtime { get { return LastMSG; } }
        #endregion

        #region --------------------------- Structures&Enums ---------------------------
        #endregion

        #region --------------------------- Construcotrs&Destructor ---------------------------
        public ACK()
        {
            MsgMemmory = new List<EmbeddedPacket>();
            LastMSG = DateTime.UtcNow;
        }
        #endregion

        #region --------------------------- Private sector ---------------------------
        /// <summary>
        /// Find index of input packet in ACK memory
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private bool Compare(EmbeddedPacket packet, out int index)
        {
            bool _res = false;
            index = 0;

            for(int i = 0; i < MsgMemmory.Count; i++)
            {
                if(MsgMemmory[i].MsgType == packet.MsgType && MsgMemmory[i].MsgID == packet.MsgID)
                {
                    _res = true;
                    index = i;
                    break;
                }
            }

            return _res;
        }

        /// <summary>
        /// Returns packet with Type and ID from income packets data
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        private EmbeddedPacket GetAckData(EmbeddedPacket packet)
        {
            EmbeddedPacket _res = packet;
            _res.MsgType = BitConverter.ToUInt32(new byte[] { packet.MsgData[3], packet.MsgData[2], packet.MsgData[1], packet.MsgData[0] }, 0);
            _res.MsgID = BitConverter.ToUInt32(new byte[] { packet.MsgData[7], packet.MsgData[6], packet.MsgData[5], packet.MsgData[4] }, 0); ;
            return _res;
        }
        #endregion

        #region --------------------------- Protected sector ---------------------------
        #endregion

        #region --------------------------- Public sector ---------------------------
        /// <summary>
        /// Save message whos needs ack into memory
        /// </summary>
        /// <param name="packet"></param>
        public void SaveMsgForAck(EmbeddedPacket packet)
        {
            MsgMemmory.Add(packet);
            MsgMemmory.TrimExcess();
            LastMSG = DateTime.UtcNow;
        }

        /// <summary>
        /// Find message in ack memory and delete it from memory
        /// </summary>
        /// <param name="packet"></param>
        public void FindACK(EmbeddedPacket packet, ref uint counter)
        {
            int _index = 0;
            if (Compare(GetAckData(packet), out _index))
            {
                MsgMemmory.RemoveAt(_index);
                MsgMemmory.TrimExcess();
                counter = 0;
            }
        }

        public void ClearMemory()
        {
            this.MsgMemmory.Clear();
        }

        /// <summary>
        /// Returns whole ACK memory or array with length 0
        /// </summary>
        public EmbeddedPacket[] GetACKmemory { get { return (MsgMemmory == null)? new EmbeddedPacket[0] : MsgMemmory.ToArray(); } }
        #endregion
    }
}
