//  =====================================================
//  The binary writer class stores values of basic value
//  types and strings to the underlying stream in binary
//  format. Values of basic value types are stored in big
//  endian format and strings using UTF-8 encoding and
//  zero byte terminated.
//  =====================================================

using System;
using System.Unicode;

namespace System.IO
{
    public class BinaryWriter : Closable
    {
        public BinaryWriter(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("provided stream is null");
            }
            this.stream = stream;
            this.stringEncoder = new Utf8Encoder(stream);
        }
        public void Close()
        {
            stream.Close();
        }
        public void Write(bool x)
        {
            Write(cast<byte>(x));
        }
        public void Write(char x)
        {
            Write(cast<uint>(x));
        }
        public void Write(string x)
        {
            if (x != null)
            {
                stringEncoder.Encode(x);
            }
            Write(cast<byte>(0u));
        }
        public void Write(sbyte x)
        {
            Write(cast<byte>(x));
        }
        public void Write(byte x)
        {
            stream.WriteByte(x);
        }
        public void Write(short x)
        {
            Write(cast<ushort>(x));
        }
        public void Write(ushort x)
        {
            byte x0 = cast<byte>(x >> 8u);
            byte x1 = cast<byte>(x);
            Write(x0);
            Write(x1);
        }
        public void Write(int x)
        {
            Write(cast<uint>(x));
        }
        public void Write(uint x)
        {
            byte x0 = cast<byte>(x >> 24u);
            byte x1 = cast<byte>(x >> 16u);
            byte x2 = cast<byte>(x >> 8u);
            byte x3 = cast<byte>(x);
            Write(x0);
            Write(x1);
            Write(x2);
            Write(x3);
        }
        public void Write(long x)
        {
            Write(cast<ulong>(x));
        }
        public void Write(ulong x)
        {
            byte x0 = cast<byte>(x >> 56u);
            byte x1 = cast<byte>(x >> 48u);
            byte x2 = cast<byte>(x >> 40u);
            byte x3 = cast<byte>(x >> 32u);
            byte x4 = cast<byte>(x >> 24u);
            byte x5 = cast<byte>(x >> 16u);
            byte x6 = cast<byte>(x >> 8u);
            byte x7 = cast<byte>(x);
            Write(x0);
            Write(x1);
            Write(x2);
            Write(x3);
            Write(x4);
            Write(x5);
            Write(x6);
            Write(x7);
        }
        public void Write(float x)
        {
            Write(FloatAsUInt(x));
        }
        public void Write(double x)
        {
            Write(DoubleAsULong(x));
        }
        public void Seek(int pos, Origin origin)
        {
            stream.Seek(pos, origin);
        }
        public int Tell()
        {
            return stream.Tell();
        }
        public Stream ContainedStream
        {
            get { return stream; }
        }
        private Stream stream;
        private Utf8Encoder stringEncoder;
    }

    [vmf=floatasuint]
    public extern uint FloatAsUInt(float x);
    [vmf=doubleasulong]
    public extern ulong DoubleAsULong(double x);
}