using CommonLang.ByteOrder;
using CommonLang.Xml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace CommonLang.IO
{

    public class InputStream : IInputStream
    {
        private Stream _stream;
        private byte[] _buff = new byte[8];

        public InputStream(Stream stream, IExternalizableFactory factory) : base(factory)
        {
            _stream = stream;
        }
        public void SetStream(Stream stream)
        {
            _stream = stream;
        }

        public override bool GetBool()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 1);
            return _buff[0] != 0;
        }

        public override byte GetU8()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 1);
            return _buff[0];
        }

        public override sbyte GetS8()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 1);
            return (sbyte)_buff[0];
        }

        public override ushort GetU16()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 2);
            int ret = 0;
            ret |= (((int)_buff[0]));
            ret |= (((int)_buff[1]) << 8);
            return (ushort)ret;
        }

        public override short GetS16()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 2);
            int ret = 0;
            ret |= (((int)_buff[0]));
            ret |= (((int)_buff[1]) << 8);
            return (short)ret;
        }

        public override uint GetU32()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 4);
            int ret = 0;
            ret |= (((int)_buff[0]));
            ret |= (((int)_buff[1]) << 8);
            ret |= (((int)_buff[2]) << 16);
            ret |= (((int)_buff[3]) << 24);
            return (uint)ret;
        }

        public override int GetS32()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 4);
            int ret = 0;
            ret |= (((int)_buff[0]));
            ret |= (((int)_buff[1]) << 8);
            ret |= (((int)_buff[2]) << 16);
            ret |= (((int)_buff[3]) << 24);
            return ret;
        }

        public override ulong GetU64()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 8);
            ulong ret = 0;
            ret |= (((ulong)_buff[0]));
            ret |= (((ulong)_buff[1]) << 8);
            ret |= (((ulong)_buff[2]) << 16);
            ret |= (((ulong)_buff[3]) << 24);
            ret |= (((ulong)_buff[4]) << 32);
            ret |= (((ulong)_buff[5]) << 40);
            ret |= (((ulong)_buff[6]) << 48);
            ret |= (((ulong)_buff[7]) << 56);
            return ret;
        }

        public override long GetS64()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 8);
            long ret = 0;
            ret |= (((long)_buff[0]));
            ret |= (((long)_buff[1]) << 8);
            ret |= (((long)_buff[2]) << 16);
            ret |= (((long)_buff[3]) << 24);
            ret |= (((long)_buff[4]) << 32);
            ret |= (((long)_buff[5]) << 40);
            ret |= (((long)_buff[6]) << 48);
            ret |= (((long)_buff[7]) << 56);
            return ret;
        }

        public override float GetF32()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 4);
            return System.BitConverter.ToSingle(_buff, 0);
        }

        public override char GetUnicode()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 2);
            return System.BitConverter.ToChar(_buff, 0);
        }

        public override double GetF64()
        {
            IOUtil.ReadToEnd(_stream, _buff, 0, 8);
            return System.BitConverter.ToDouble(_buff, 0);
        }

        public override string GetUTF()
        {
            int len = GetU16();
            if (len == UInt16.MaxValue)
            {
                return null;
            }
            if (len > 0)
            {
                byte[] buff = new byte[len];
                IOUtil.ReadToEnd(_stream, buff, 0, len);
                return utfenc.GetString(buff, 0, len);
            }
            return "";
        }


        public override byte[] GetBytes()
        {
            int len = GetS32();
            if (len > BYTES_LIMIT) { throw new IOException("Bytes overflow : " + len); }
            if (len < 0) return null;
            if (len == 0) return new byte[0];
            byte[] ret = new byte[len];
            IOUtil.ReadToEnd(_stream, ret, 0, len);
            return ret;
        }

        public override void GetRawData(byte[] buff, int offset, int count)
        {
            IOUtil.ReadToEnd(_stream, buff, offset, count);
        }
    }
    
    public class OutputStream : IOutputStream
    {
        private Stream _stream;

        public OutputStream(Stream stream, IExternalizableFactory factory):base(factory)
        {
            _stream = stream;
        }

        public override long GetBuffPos()
        {
            return (this._stream == null) ? 0 : this._stream.Position;
        }

        public void SetStream(Stream stream)
        {
            _stream = stream;
        }

        public override void PutBool(bool value)
        {
            _stream.WriteByte((byte)(value ? 1 : 0));
        }

        public override void PutU8(byte value)
        {
            _stream.WriteByte(value);
        }

        public override void PutS8(sbyte value)
        {
            _stream.WriteByte((byte)value);
        }

        public override void PutU16(ushort value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
        }

        public override void PutS16(short value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
        }

        public override void PutU32(uint value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
            _stream.WriteByte((byte)(value >> 16));
            _stream.WriteByte((byte)(value >> 24));
        }

        public override void PutS32(int value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
            _stream.WriteByte((byte)(value >> 16));
            _stream.WriteByte((byte)(value >> 24));
        }

        public override void PutU64(ulong value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
            _stream.WriteByte((byte)(value >> 16));
            _stream.WriteByte((byte)(value >> 24));
            _stream.WriteByte((byte)(value >> 32));
            _stream.WriteByte((byte)(value >> 40));
            _stream.WriteByte((byte)(value >> 48));
            _stream.WriteByte((byte)(value >> 56));
        }

        public override void PutS64(long value)
        {
            _stream.WriteByte((byte)(value));
            _stream.WriteByte((byte)(value >> 8));
            _stream.WriteByte((byte)(value >> 16));
            _stream.WriteByte((byte)(value >> 24));
            _stream.WriteByte((byte)(value >> 32));
            _stream.WriteByte((byte)(value >> 40));
            _stream.WriteByte((byte)(value >> 48));
            _stream.WriteByte((byte)(value >> 56));
        }

        public override void PutF32(float value)
        {
            byte[] buff = BitConverter.GetBytes(value);
            _stream.Write(buff, 0, 4);
        }

        public override void PutF64(double value)
        {
            byte[] buff = BitConverter.GetBytes(value);
            _stream.Write(buff, 0, 8);
        }

        public override void PutUnicode(char value)
        {
            byte[] buff = BitConverter.GetBytes(value);
            _stream.Write(buff, 0, 2);
        }

        public override void PutUTF(string str)
        {
            if (str == null)
            {
                PutU16(UInt16.MaxValue);
            }
            else if (str.Length == 0)
            {
                PutU16(0);
            }
            else
            {
                byte[] buff = utfenc.GetBytes(str);
                if (buff.Length >= UInt16.MaxValue)
                {
                    throw new IOException("PutUTF overflow : " + str + "\nSize=" + buff.Length);
                }
                PutU16((ushort)buff.Length);
                _stream.Write(buff, 0, buff.Length);
            }
        }

        public override void PutBytes(byte[] bytes)
        {
            if (bytes == null)
            {
                PutS32(-1);
            }
            else if (bytes.Length == 0)
            {
                PutS32(0);
            }
            else
            {
                int len = bytes.Length;
                if (len > BYTES_LIMIT) { throw new IOException("Bytes overflow : " + len); }
                PutS32(bytes.Length);
                _stream.Write(bytes, 0, bytes.Length);
            }
        }

        public override void PutRawData(byte[] bytes, int offset, int count)
        {
            _stream.Write(bytes, offset, count);
        }
    }

}