using FishNet.Serializing;
using System;
using UnityEngine;
namespace FishNet.Managing.Transporting
{
    internal class SplitReader
    {
        #region Private.
        /// 
        /// Tick split is for.
        /// Tick must be a negative value so that it's impossible for the first tick to align.
        /// 
        private long _tick = -1;
        /// 
        /// Expected number of splits.
        /// 
        private int _expectedMessages;
        /// 
        /// Number of splits received so far.
        /// 
        private ushort _receivedMessages;
        /// 
        /// Writer containing split packet combined.
        /// 
        private PooledWriter _writer = WriterPool.GetWriter();
        #endregion
        internal SplitReader()
        {
            //Increase capacity to reduce the chance of resizing.
            _writer.EnsureBufferCapacity(20000);
        }
        /// 
        /// Gets split header values.
        /// 
        internal void GetHeader(PooledReader reader, out int expectedMessages)
        {
            expectedMessages = reader.ReadInt32();
        }
        /// 
        /// Combines split data.
        /// 
        internal void Write(uint tick, PooledReader reader, int expectedMessages)
        {
            //New tick which means new split.
            if (tick != _tick)
                Reset(tick, expectedMessages);
            /* This is just a guess as to how large the end
             * message could be. If the writer is not the minimum
             * of this length then resize it. */
            int estimatedBufferSize = (expectedMessages * 1500);
            if (_writer.Capacity < estimatedBufferSize)
                _writer.EnsureBufferCapacity(estimatedBufferSize);
            /* Empty remainder of reader into the writer.
             * It does not matter if parts of the reader
             * contain data added after the split because
             * once the split is fully combined the data
             * is parsed as though it came in as one message,
             * which is how data is normally read. */
            ArraySegment data = reader.ReadArraySegment(reader.Remaining);
            _writer.WriteArraySegment(data);
            _receivedMessages++;
        }
        /// 
        /// Returns if all split messages have been received.
        /// 
        /// 
        internal ArraySegment GetFullMessage()
        {
            if (_receivedMessages < _expectedMessages)
            {
                return default(ArraySegment);
            }
            else
            {
                ArraySegment segment = _writer.GetArraySegment();
                Reset();
                return segment;
            }
        }
        private void Reset(uint tick = 0, int expectedMessages = 0)
        {
            _tick = tick;
            _receivedMessages = 0;
            _expectedMessages = expectedMessages;
            _writer.Reset();
        }
    }
}