package fasthttp

import (
	
	
	
	

	
	
	
)

// Supported compression levels.
const (
	CompressBrotliNoCompression   = 0
	CompressBrotliBestSpeed       = brotli.BestSpeed
	CompressBrotliBestCompression = brotli.BestCompression

	// Choose a default brotli compression level comparable to
	// CompressDefaultCompression (gzip 6)
	// See: https://github.com/valyala/fasthttp/issues/798#issuecomment-626293806
	CompressBrotliDefaultCompression = 4
)

func acquireBrotliReader( io.Reader) (*brotli.Reader, error) {
	 := brotliReaderPool.Get()
	if  == nil {
		return brotli.NewReader(), nil
	}
	 := .(*brotli.Reader)
	if  := .Reset();  != nil {
		return nil, 
	}
	return , nil
}

func releaseBrotliReader( *brotli.Reader) {
	brotliReaderPool.Put()
}

var brotliReaderPool sync.Pool

func acquireStacklessBrotliWriter( io.Writer,  int) stackless.Writer {
	 := normalizeBrotliCompressLevel()
	 := stacklessBrotliWriterPoolMap[]
	 := .Get()
	if  == nil {
		return stackless.NewWriter(, func( io.Writer) stackless.Writer {
			return acquireRealBrotliWriter(, )
		})
	}
	 := .(stackless.Writer)
	.Reset()
	return 
}

func releaseStacklessBrotliWriter( stackless.Writer,  int) {
	.Close()
	 := normalizeBrotliCompressLevel()
	 := stacklessBrotliWriterPoolMap[]
	.Put()
}

func acquireRealBrotliWriter( io.Writer,  int) *brotli.Writer {
	 := normalizeBrotliCompressLevel()
	 := realBrotliWriterPoolMap[]
	 := .Get()
	if  == nil {
		 := brotli.NewWriterLevel(, )
		return 
	}
	 := .(*brotli.Writer)
	.Reset()
	return 
}

func releaseRealBrotliWriter( *brotli.Writer,  int) {
	.Close()
	 := normalizeBrotliCompressLevel()
	 := realBrotliWriterPoolMap[]
	.Put()
}

var (
	stacklessBrotliWriterPoolMap = newCompressWriterPoolMap()
	realBrotliWriterPoolMap      = newCompressWriterPoolMap()
)

// AppendBrotliBytesLevel appends brotlied src to dst using the given
// compression level and returns the resulting dst.
//
// Supported compression levels are:
//
//   - CompressBrotliNoCompression
//   - CompressBrotliBestSpeed
//   - CompressBrotliBestCompression
//   - CompressBrotliDefaultCompression
func (,  []byte,  int) []byte {
	 := &byteSliceWriter{}
	WriteBrotliLevel(, , ) //nolint:errcheck
	return .b
}

// WriteBrotliLevel writes brotlied p to w using the given compression level
// and returns the number of compressed bytes written to w.
//
// Supported compression levels are:
//
//   - CompressBrotliNoCompression
//   - CompressBrotliBestSpeed
//   - CompressBrotliBestCompression
//   - CompressBrotliDefaultCompression
func ( io.Writer,  []byte,  int) (int, error) {
	switch .(type) {
	case *byteSliceWriter,
		*bytes.Buffer,
		*bytebufferpool.ByteBuffer:
		// These writers don't block, so we can just use stacklessWriteBrotli
		 := &compressCtx{
			w:     ,
			p:     ,
			level: ,
		}
		stacklessWriteBrotli()
		return len(), nil
	default:
		 := acquireStacklessBrotliWriter(, )
		,  := .Write()
		releaseStacklessBrotliWriter(, )
		return , 
	}
}

var stacklessWriteBrotli = stackless.NewFunc(nonblockingWriteBrotli)

func nonblockingWriteBrotli( interface{}) {
	 := .(*compressCtx)
	 := acquireRealBrotliWriter(.w, .level)

	.Write(.p) //nolint:errcheck // no way to handle this error anyway

	releaseRealBrotliWriter(, .level)
}

// WriteBrotli writes brotlied p to w and returns the number of compressed
// bytes written to w.
func ( io.Writer,  []byte) (int, error) {
	return WriteBrotliLevel(, , CompressBrotliDefaultCompression)
}

// AppendBrotliBytes appends brotlied src to dst and returns the resulting dst.
func (,  []byte) []byte {
	return AppendBrotliBytesLevel(, , CompressBrotliDefaultCompression)
}

// WriteUnbrotli writes unbrotlied p to w and returns the number of uncompressed
// bytes written to w.
func ( io.Writer,  []byte) (int, error) {
	 := &byteSliceReader{}
	,  := acquireBrotliReader()
	if  != nil {
		return 0, 
	}
	,  := copyZeroAlloc(, )
	releaseBrotliReader()
	 := int()
	if int64() !=  {
		return 0, fmt.Errorf("too much data unbrotlied: %d", )
	}
	return , 
}

// AppendUnbrotliBytes appends unbrotlied src to dst and returns the resulting dst.
func (,  []byte) ([]byte, error) {
	 := &byteSliceWriter{}
	,  := WriteUnbrotli(, )
	return .b, 
}

// normalizes compression level into [0..11], so it could be used as an index
// in *PoolMap.
func normalizeBrotliCompressLevel( int) int {
	// -2 is the lowest compression level - CompressHuffmanOnly
	// 9 is the highest compression level - CompressBestCompression
	if  < 0 ||  > 11 {
		 = CompressBrotliDefaultCompression
	}
	return 
}