using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;

namespace Inspectron.HawkEye
{
    public class DefragmentedPacket
    {
        private readonly uint _packetSize;
        private byte[] _receivedParts = null;
        //ConcurrentDictionary<uint,byte[]> _packetParts = new ConcurrentDictionary<uint, byte[]>();
        private byte[][] _packetParts;
        public DefragmentedPacket(uint packetSize)
        {
            _packetSize = packetSize;
            _packetParts=new byte[30000][];
        }

        private int _uniquePackets=0;
        public void Defragment(byte[] data)
        {
            var packetStart = -1;

            for (int i = 0; i < data.Length; i++)
            {
                if (BitConverter.ToUInt32(data, i) == 114455)
                {
                    packetStart = i;
                    break;
                };
            }

            if (packetStart == -1) return;

          MemoryStream ms = new MemoryStream(data,packetStart, data.Length - packetStart);
            BinaryReader br = new BinaryReader(ms);
            br.ReadUInt32();//packetStart
            var packetType = br.ReadUInt32();
            var sequenceId = br.ReadUInt32();
            var packetNumber = br.ReadUInt32();

            var totalPackets = br.ReadUInt32();

            if(_receivedParts==null)_receivedParts=new byte[totalPackets];
            if (_receivedParts[packetNumber] == 1) return;
            _receivedParts[packetNumber] = 1;
            Interlocked.Increment(ref _uniquePackets);
            var dataLen = br.ReadInt32();

            var dataBytes = br.ReadBytes(dataLen);


            _packetParts[packetNumber] = dataBytes;

        }

        public byte[] Reconstruct()
        {
            var parts = _receivedParts.Length;
            byte[] res = new byte[parts*_packetSize];
            Stopwatch sw = Stopwatch.StartNew();
            int resSize = 0;
            for (int i = 0; i < parts; i++)
            {
                //if (_packetParts.ContainsKey((uint) i))
                if (_packetParts[i]!=null)
                {
                    var packetData = _packetParts[(uint) i];
                    
                    Array.Copy(packetData, 0,res, resSize, packetData.Length);
                    resSize += packetData.Length;
                }
                else
                {
                    resSize += (int)_packetSize-20/*headerSize*/;
                }
            }

            sw.Stop();
            

            Array.Resize(ref res,resSize);

            return res;

        }

        public bool IsComplete
        {
            get
            {
                if (_receivedParts == null) return false;
                return _uniquePackets == _receivedParts.Length;
                //return _receivedParts.All(x => x == 1);
            }
        }

    }
}