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

namespace InABox.Core
{
    public class FastBinaryWriter : IDisposable
    {
        private List<byte[]> _data = new List<byte[]>();

        public void Dispose()
        {
            _data.Clear();
        }

        public byte[] GetBuffer()
        {
            var result = new byte[_data.Sum(a => a.Length)];
            var offset = 0;
            foreach (var array in _data)
            {
                Buffer.BlockCopy(array, 0, result, offset, array.Length);
                offset += array.Length;
            }

            return result;
        }

        public void Write(bool value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(byte value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(short value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(int value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(long value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(float value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        public void Write(double value)
        {
            _data.Add(BitConverter.GetBytes(value));
        }

        protected void Write7BitEncodedInt(int value)
        {
            // Write out an int 7 bits at a time.  The high bit of the byte,
            // when on, tells reader to continue reading more bytes.
            var v = (uint)value; // support negative numbers
            while (v >= 0x80)
            {
                Write((byte)(v | 0x80));
                v >>= 7;
            }

            Write((byte)v);
        }

        public void Write(string value)
        {
            Write7BitEncodedInt(value.Length);
            _data.Add(Encoding.UTF8.GetBytes(value));
        }

        public void Write(DateTime value)
        {
            Write(value.ToBinary());
        }

        public void Write(TimeSpan value)
        {
            Write(value.Ticks);
        }

        public void Write(Guid value)
        {
            _data.Add(value.ToByteArray());
        }

        public void Write(byte[] value)
        {
            _data.Add(value);
        }
    }
}