// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.

package zstd

import (
	
	
	
)

// ZipMethodWinZip is the method for Zstandard compressed data inside Zip files for WinZip.
// See https://www.winzip.com/win/en/comp_info.html
const ZipMethodWinZip = 93

// ZipMethodPKWare is the original method number used by PKWARE to indicate Zstandard compression.
// Deprecated: This has been deprecated by PKWARE, use ZipMethodWinZip instead for compression.
// See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
const ZipMethodPKWare = 20

// zipReaderPool is the default reader pool.
var zipReaderPool = sync.Pool{New: func() any {
	,  := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
	if  != nil {
		panic()
	}
	return 
}}

// newZipReader creates a pooled zip decompressor.
func newZipReader( ...DOption) func( io.Reader) io.ReadCloser {
	 := &zipReaderPool
	if len() > 0 {
		 = append([]DOption{WithDecoderLowmem(true), WithDecoderMaxWindow(128 << 20)}, ...)
		// Force concurrency 1
		 = append(, WithDecoderConcurrency(1))
		// Create our own pool
		 = &sync.Pool{}
	}
	return func( io.Reader) io.ReadCloser {
		,  := .Get().(*Decoder)
		if  {
			.Reset()
		} else {
			,  := NewReader(, ...)
			if  != nil {
				panic()
			}
			 = 
		}
		return &pooledZipReader{dec: , pool: }
	}
}

type pooledZipReader struct {
	mu   sync.Mutex // guards Close and Read
	pool *sync.Pool
	dec  *Decoder
}

func ( *pooledZipReader) ( []byte) ( int,  error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .dec == nil {
		return 0, errors.New("read after close or EOF")
	}
	,  := .dec.Read()
	if  == io.EOF {
		.dec.Reset(nil)
		.pool.Put(.dec)
		.dec = nil
	}
	return , 
}

func ( *pooledZipReader) () error {
	.mu.Lock()
	defer .mu.Unlock()
	var  error
	if .dec != nil {
		 = .dec.Reset(nil)
		.pool.Put(.dec)
		.dec = nil
	}
	return 
}

type pooledZipWriter struct {
	mu   sync.Mutex // guards Close and Read
	enc  *Encoder
	pool *sync.Pool
}

func ( *pooledZipWriter) ( []byte) ( int,  error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .enc == nil {
		return 0, errors.New("Write after Close")
	}
	return .enc.Write()
}

func ( *pooledZipWriter) () error {
	.mu.Lock()
	defer .mu.Unlock()
	var  error
	if .enc != nil {
		 = .enc.Close()
		.pool.Put(.enc)
		.enc = nil
	}
	return 
}

// ZipCompressor returns a compressor that can be registered with zip libraries.
// The provided encoder options will be used on all encodes.
func ( ...EOption) func( io.Writer) (io.WriteCloser, error) {
	var  sync.Pool
	return func( io.Writer) (io.WriteCloser, error) {
		,  := .Get().(*Encoder)
		if  {
			.Reset()
		} else {
			var  error
			,  = NewWriter(, ...)
			if  != nil {
				return nil, 
			}
		}
		return &pooledZipWriter{enc: , pool: &}, nil
	}
}

// ZipDecompressor returns a decompressor that can be registered with zip libraries.
// See ZipCompressor for example.
// Options can be specified. WithDecoderConcurrency(1) is forced,
// and by default a 128MB maximum decompression window is specified.
// The window size can be overridden if required.
func ( ...DOption) func( io.Reader) io.ReadCloser {
	return newZipReader(...)
}