package avro

import (
	
	
	
)

// WriterFunc is a function used to customize the Writer.
type WriterFunc func(w *Writer)

// WithWriterConfig specifies the configuration to use with a writer.
func ( API) WriterFunc {
	return func( *Writer) {
		.cfg = .(*frozenConfig)
	}
}

// Writer is an Avro specific io.Writer.
type Writer struct {
	cfg   *frozenConfig
	out   io.Writer
	buf   []byte
	Error error
}

// NewWriter creates a new Writer.
func ( io.Writer,  int,  ...WriterFunc) *Writer {
	 := &Writer{
		cfg:   DefaultConfig.(*frozenConfig),
		out:   ,
		buf:   make([]byte, 0, ),
		Error: nil,
	}

	for ,  := range  {
		()
	}

	return 
}

// Reset resets the Writer with a new io.Writer attached.
func ( *Writer) ( io.Writer) {
	.out = 
	.buf = .buf[:0]
}

// Buffered returns the number of buffered bytes.
func ( *Writer) () int {
	return len(.buf)
}

// Buffer gets the Writer buffer.
func ( *Writer) () []byte {
	return .buf
}

// Flush writes any buffered data to the underlying io.Writer.
func ( *Writer) () error {
	if .out == nil {
		return nil
	}
	if .Error != nil {
		return .Error
	}

	,  := .out.Write(.buf)
	if  < len(.buf) &&  == nil {
		 = io.ErrShortWrite
	}
	if  != nil {
		if .Error == nil {
			.Error = 
		}
		return 
	}

	.buf = .buf[:0]

	return nil
}

func ( *Writer) ( byte) {
	.buf = append(.buf, )
}

// Write writes raw bytes to the Writer.
func ( *Writer) ( []byte) (int, error) {
	.buf = append(.buf, ...)
	return len(), nil
}

// WriteBool writes a Bool to the Writer.
func ( *Writer) ( bool) {
	if  {
		.writeByte(0x01)
		return
	}
	.writeByte(0x00)
}

// WriteInt writes an Int to the Writer.
func ( *Writer) ( int32) {
	 := uint64((uint32() << 1) ^ uint32(>>31))
	.encodeInt()
}

// WriteLong writes a Long to the Writer.
func ( *Writer) ( int64) {
	 := (uint64() << 1) ^ uint64(>>63)
	.encodeInt()
}

func ( *Writer) ( uint64) {
	if  == 0 {
		.writeByte(0)
		return
	}

	for  > 0 {
		 := byte() & 0x7F
		 >>= 7

		if  != 0 {
			 |= 0x80
		}
		.writeByte()
	}
}

// WriteFloat writes a Float to the Writer.
func ( *Writer) ( float32) {
	 := make([]byte, 4)
	binary.LittleEndian.PutUint32(, math.Float32bits())

	.buf = append(.buf, ...)
}

// WriteDouble writes a Double to the Writer.
func ( *Writer) ( float64) {
	 := make([]byte, 8)
	binary.LittleEndian.PutUint64(, math.Float64bits())

	.buf = append(.buf, ...)
}

// WriteBytes writes Bytes to the Writer.
func ( *Writer) ( []byte) {
	.WriteLong(int64(len()))
	.buf = append(.buf, ...)
}

// WriteString reads a String to the Writer.
func ( *Writer) ( string) {
	.WriteLong(int64(len()))
	.buf = append(.buf, ...)
}

// WriteBlockHeader writes a Block Header to the Writer.
func ( *Writer) (,  int64) {
	if  > 0 && !.cfg.config.DisableBlockSizeHeader {
		.WriteLong(-)
		.WriteLong()
		return
	}
	.WriteLong()
}

// WriteBlockCB writes a block using the callback.
func ( *Writer) ( func( *Writer) int64) int64 {
	var  [18]byte
	 := len(.buf)

	// Write dummy header
	_, _ = .Write([:])

	// Write block data
	 := len(.buf)
	 := ()
	 := int64(len(.buf) - )

	// Take a reference to the block data
	 := .buf[:len(.buf)]

	// Rewrite the header
	.buf = .buf[:]
	.WriteBlockHeader(, )

	// Copy the block data back to its position
	.buf = append(.buf, ...)

	return 
}