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

namespace iSTP_Embedded
{
    public partial class EmbeddedPacket : IComparable<int>
    {
        public const UInt32 PacketStart = 0x23232323; //####
        

        public const int MaxMsgDataLength = 8192;
        
        #region iSTP packet items
        public static UInt32 MsgCounter = 0;
        public UInt32 MsgNumber;
        public Double MsgTimeStamp;
        public UInt32 MsgType;
        public UInt32 MsgID;
        public Int32 MsgLength;
        public Byte[] MsgData = null;
        public UInt32 MsgChecksum;
        #endregion

        public EmbeddedPacket()
        {
            this.MsgNumber = 0;
            this.MsgTimeStamp = 0;
            this.MsgType = 0;
            this.MsgID = 0;
            this.MsgLength = 0;
            this.MsgData = null;
            this.MsgChecksum = 0;
        }

        public EmbeddedPacket(uint number, uint type, uint id, byte[] data)
        {
            this.MsgNumber = number;
            this.MsgType = type;
            this.MsgID = id;
            if (data == null)
                this.MsgLength = 0;
            else
            {
                MsgData = new byte[data.Length];
                data.CopyTo(MsgData, 0);
                MsgLength = MsgData.Length;
            }
        }


        public Single GetData(int Index)
        {
            return BinaryConverter.GetSingle(MsgData, (Index * sizeof(Single)));
        }

        public void SetData(int Index, Single Value)
        {
            BinaryConverter.GetBytes(MsgData, (Index * sizeof(Single)), Value);
        }

        public Single this[int Index]
        {
            get
            {
                return BinaryConverter.GetSingle(MsgData, (Index * sizeof(Single)));
            }

            set
            {
                BinaryConverter.GetBytes(MsgData, (Index * sizeof(Single)), value);
            }
        }

        public UInt32 getInt(int Index) {
            return BinaryConverter.GetUInt32(MsgData, ((int)Index * sizeof(UInt32)));
        }

        public void PrepareBuffer()
        {
            if (MsgLength > 0)
            {
                if (MsgData != null)
                {
                    if (MsgLength > MsgData.Length)
                    {
                        MsgData = new Byte[MsgLength];
                    }
                }
                else
                {
                    MsgData = new Byte[MsgLength];
                }
            }
        }

        public int CompareTo(int otherLength)
        {
            int myLength = (MsgData == null) ? 0 : MsgData.Length;

            return (myLength - otherLength);
        }

        unsafe public UInt32 CalcCRC32()
        {
            CRC32 crc = new CRC32(0xFFFFFFFF);
            for (int i = 24; i >= 0; i-=8)
                crc.AddByte((byte)((MsgNumber >> i) & 0xFF));
            
            double ts = MsgTimeStamp;
            ulong timestamp = *((ulong*)&ts);
            for (int i = 56; i >= 0; i-=8)
                crc.AddByte((byte)(( timestamp>> i) & 0xFF));

            for (int i = 24; i >= 0; i-=8)
                crc.AddByte((byte)((MsgType >> i) & 0xFF));

            for (int i = 24; i >= 0; i-=8)
                crc.AddByte((byte)((MsgID >> i) & 0xFF));

            for (int i = 24; i >= 0; i-=8)
                crc.AddByte((byte)((MsgLength >> i) & 0xFF));

            if (MsgLength > 0)
            {
                for (int i = 0; i < MsgLength; i++)
                    crc.AddByte(MsgData[i]);
            }
            /* XOR the output value */
            crc.inverse();
            crc.reverse32();
            crc.inverse();

            return (crc.Current);
        }

        public void CloneTo(EmbeddedPacket packet)
        {
            packet.MsgNumber = this.MsgNumber;
            packet.MsgType = this.MsgType;
            packet.MsgID = this.MsgID;
            packet.MsgLength = this.MsgLength;
            packet.PrepareBuffer();
            packet.MsgTimeStamp = this.MsgTimeStamp;

            for (int i = 0; i < packet.MsgLength; i++)
            {
                packet.MsgData[i] = this.MsgData[i];
            }
            packet.MsgChecksum = this.MsgChecksum;
        }
    }
}
