package brotli

import (
	
	
)

const (
	BestSpeed          = 0
	BestCompression    = 11
	DefaultCompression = 6
)

// WriterOptions configures Writer.
type WriterOptions struct {
	// Quality controls the compression-speed vs compression-density trade-offs.
	// The higher the quality, the slower the compression. Range is 0 to 11.
	Quality int
	// LGWin is the base 2 logarithm of the sliding window size.
	// Range is 10 to 24. 0 indicates automatic configuration based on Quality.
	LGWin int
}

var (
	errEncode       = errors.New("brotli: encode error")
	errWriterClosed = errors.New("brotli: Writer is closed")
)

// Writes to the returned writer are compressed and written to dst.
// It is the caller's responsibility to call Close on the Writer when done.
// Writes may be buffered and not flushed until Close.
func ( io.Writer) *Writer {
	return NewWriterLevel(, DefaultCompression)
}

// NewWriterLevel is like NewWriter but specifies the compression level instead
// of assuming DefaultCompression.
// The compression level can be DefaultCompression or any integer value between
// BestSpeed and BestCompression inclusive.
func ( io.Writer,  int) *Writer {
	return NewWriterOptions(, WriterOptions{
		Quality: ,
	})
}

// NewWriterOptions is like NewWriter but specifies WriterOptions
func ( io.Writer,  WriterOptions) *Writer {
	 := new(Writer)
	.options = 
	.Reset()
	return 
}

// Reset discards the Writer's state and makes it equivalent to the result of
// its original state from NewWriter or NewWriterLevel, but writing to dst
// instead. This permits reusing a Writer rather than allocating a new one.
func ( *Writer) ( io.Writer) {
	encoderInitState()
	.params.quality = .options.Quality
	if .options.LGWin > 0 {
		.params.lgwin = uint(.options.LGWin)
	}
	.dst = 
	.err = nil
}

func ( *Writer) ( []byte,  int) ( int,  error) {
	if .dst == nil {
		return 0, errWriterClosed
	}
	if .err != nil {
		return 0, .err
	}

	for {
		 := uint(len())
		 := 
		 := encoderCompressStream(, , &, &)
		 := len() - int()
		 = [:]
		 += 
		if ! {
			return , errEncode
		}

		if len() == 0 || .err != nil {
			return , .err
		}
	}
}

// Flush outputs encoded data for all input provided to Write. The resulting
// output can be decoded to match all input before Flush, but the stream is
// not yet complete until after Close.
// Flush has a negative impact on compression.
func ( *Writer) () error {
	,  := .writeChunk(nil, operationFlush)
	return 
}

// Close flushes remaining data to the decorated writer.
func ( *Writer) () error {
	// If stream is already closed, it is reported by `writeChunk`.
	,  := .writeChunk(nil, operationFinish)
	.dst = nil
	return 
}

// Write implements io.Writer. Flush or Close must be called to ensure that the
// encoded bytes are actually flushed to the underlying Writer.
func ( *Writer) ( []byte) ( int,  error) {
	return .writeChunk(, operationProcess)
}

type nopCloser struct {
	io.Writer
}

func (nopCloser) () error { return nil }