// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
// Based on work by Yann Collet, released under BSD License.

package zstd

import (
	
	
	
)

type seq struct {
	litLen   uint32
	matchLen uint32
	offset   uint32

	// Codes are stored here for the encoder
	// so they only have to be looked up once.
	llCode, mlCode, ofCode uint8
}

type seqVals struct {
	ll, ml, mo int
}

func ( seq) () string {
	if .offset <= 3 {
		if .offset == 0 {
			return fmt.Sprint("litLen:", .litLen, ", matchLen:", .matchLen+zstdMinMatch, ", offset: INVALID (0)")
		}
		return fmt.Sprint("litLen:", .litLen, ", matchLen:", .matchLen+zstdMinMatch, ", offset:", .offset, " (repeat)")
	}
	return fmt.Sprint("litLen:", .litLen, ", matchLen:", .matchLen+zstdMinMatch, ", offset:", .offset-3, " (new)")
}

type seqCompMode uint8

const (
	compModePredefined seqCompMode = iota
	compModeRLE
	compModeFSE
	compModeRepeat
)

type sequenceDec struct {
	// decoder keeps track of the current state and updates it from the bitstream.
	fse    *fseDecoder
	state  fseState
	repeat bool
}

// init the state of the decoder with input from stream.
func ( *sequenceDec) ( *bitReader) error {
	if .fse == nil {
		return errors.New("sequence decoder not defined")
	}
	.state.init(, .fse.actualTableLog, .fse.dt[:1<<.fse.actualTableLog])
	return nil
}

// sequenceDecs contains all 3 sequence decoders and their state.
type sequenceDecs struct {
	litLengths   sequenceDec
	offsets      sequenceDec
	matchLengths sequenceDec
	prevOffset   [3]int
	dict         []byte
	literals     []byte
	out          []byte
	nSeqs        int
	br           *bitReader
	seqSize      int
	windowSize   int
	maxBits      uint8
	maxSyncLen   uint64
}

// initialize all 3 decoders from the stream input.
func ( *sequenceDecs) ( *bitReader,  *history,  []byte) error {
	if  := .litLengths.init();  != nil {
		return errors.New("litLengths:" + .Error())
	}
	if  := .offsets.init();  != nil {
		return errors.New("offsets:" + .Error())
	}
	if  := .matchLengths.init();  != nil {
		return errors.New("matchLengths:" + .Error())
	}
	.br = 
	.prevOffset = .recentOffsets
	.maxBits = .litLengths.fse.maxBits + .offsets.fse.maxBits + .matchLengths.fse.maxBits
	.windowSize = .windowSize
	.out = 
	.dict = nil
	if .dict != nil {
		.dict = .dict.content
	}
	return nil
}

func ( *sequenceDecs) () {
	if  := .litLengths.fse;  != nil && !.preDefined {
		fseDecoderPool.Put()
		.litLengths.fse = nil
	}
	if  := .offsets.fse;  != nil && !.preDefined {
		fseDecoderPool.Put()
		.offsets.fse = nil
	}
	if  := .matchLengths.fse;  != nil && !.preDefined {
		fseDecoderPool.Put()
		.matchLengths.fse = nil
	}
}

// execute will execute the decoded sequence with the provided history.
// The sequence must be evaluated before being sent.
func ( *sequenceDecs) ( []seqVals,  []byte) error {
	if len(.dict) == 0 {
		return .executeSimple(, )
	}

	// Ensure we have enough output size...
	if len(.out)+.seqSize > cap(.out) {
		 := .seqSize + len(.out)
		.out = append(.out, make([]byte, )...)
		.out = .out[:len(.out)-]
	}

	if debugDecoder {
		printf("Execute %d seqs with hist %d, dict %d, literals: %d into %d bytes\n", len(), len(), len(.dict), len(.literals), .seqSize)
	}

	var  = len(.out)
	 := .out[:+.seqSize]

	for ,  := range  {
		// Add literals
		copy([:], .literals[:.ll])
		 += .ll
		.literals = .literals[.ll:]

		// Copy from dictionary...
		if .mo > +len() || .mo > .windowSize {
			if len(.dict) == 0 {
				return fmt.Errorf("match offset (%d) bigger than current history (%d)", .mo, +len())
			}

			// we may be in dictionary.
			 := len(.dict) - (.mo - ( + len()))
			if  < 0 ||  >= len(.dict) {
				return fmt.Errorf("match offset (%d) bigger than current history+dict (%d)", .mo, +len()+len(.dict))
			}
			 :=  + .ml
			if  > len(.dict) {
				 := len(.dict) - 
				copy([:], .dict[:])
				 += 
				.ml -= 
			} else {
				copy([:], .dict[:])
				 +=  - 
				continue
			}
		}

		// Copy from history.
		if  := .mo - ;  > 0 {
			// v is the start position in history from end.
			 := len() - 
			if .ml >  {
				// Some goes into current block.
				// Copy remainder of history
				copy([:], [:])
				 += 
				.ml -= 
			} else {
				copy([:], [:+.ml])
				 += .ml
				continue
			}
		}
		// We must be in current buffer now
		if .ml > 0 {
			 :=  - .mo
			if .ml <= - {
				// No overlap
				copy([:], [:+.ml])
				 += .ml
				continue
			} else {
				// Overlapping copy
				// Extend destination slice and copy one byte at the time.
				 := [ : +.ml]
				 := [:]
				 = [:len()]
				 += len()
				// Destination is the space we just added.
				for  := range  {
					[] = []
				}
			}
		}
	}

	// Add final literals
	copy([:], .literals)
	if debugDecoder {
		 += len(.literals)
		if  != len() {
			panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(), , .seqSize))
		}
	}
	.out = 

	return nil
}

// decode sequences from the stream with the provided history.
func ( *sequenceDecs) ( []byte) error {
	,  := .decodeSyncSimple()
	if  {
		return 
	}

	 := .br
	 := .nSeqs
	 := len(.out)
	// Grab full sizes tables, to avoid bounds checks.
	, ,  := .litLengths.fse.dt[:maxTablesize], .matchLengths.fse.dt[:maxTablesize], .offsets.fse.dt[:maxTablesize]
	, ,  := .litLengths.state.state, .matchLengths.state.state, .offsets.state.state
	 := .out
	 := min(.windowSize, maxCompressedBlockSize)

	if debugDecoder {
		println("decodeSync: decoding", , "sequences", .remain(), "bits remain on stream")
	}
	for  :=  - 1;  >= 0; -- {
		if .overread() {
			printf("reading sequence %d, exceeded available data. Overread by %d\n", -, -.remain())
			return io.ErrUnexpectedEOF
		}
		var , ,  int
		if .cursor > 4+((maxOffsetBits+16+16)>>3) {
			// inlined function:
			// ll, mo, ml = s.nextFast(br, llState, mlState, ofState)

			// Final will not read from stream.
			var , ,  uint8
			,  = .final()
			,  = .final()
			,  = .final()

			// extra bits are stored in reverse order.
			.fillFast()
			 += .getBits()
			if .maxBits > 32 {
				.fillFast()
			}
			 += .getBits()
			 += .getBits()

			if  > 1 {
				.prevOffset[2] = .prevOffset[1]
				.prevOffset[1] = .prevOffset[0]
				.prevOffset[0] = 
			} else {
				// mo = s.adjustOffset(mo, ll, moB)
				// Inlined for rather big speedup
				if  == 0 {
					// There is an exception though, when current sequence's literals_length = 0.
					// In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
					// an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
					++
				}

				if  == 0 {
					 = .prevOffset[0]
				} else {
					var  int
					if  == 3 {
						 = .prevOffset[0] - 1
					} else {
						 = .prevOffset[]
					}

					if  == 0 {
						// 0 is not valid; input is corrupted; force offset to 1
						println("WARNING: temp was 0")
						 = 1
					}

					if  != 1 {
						.prevOffset[2] = .prevOffset[1]
					}
					.prevOffset[1] = .prevOffset[0]
					.prevOffset[0] = 
					 = 
				}
			}
			.fillFast()
		} else {
			, ,  = .next(, , , )
			.fill()
		}

		if debugSequences {
			println("Seq", --1, "Litlen:", , "mo:", , "(abs) ml:", )
		}

		if  > len(.literals) {
			return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", , len(.literals))
		}
		 :=  +  + len()
		if - >  {
			return fmt.Errorf("output bigger than max block size (%d)", )
		}
		if  > cap() {
			// Not enough size, which can happen under high volume block streaming conditions
			// but could be if destination slice is too small for sync operations.
			// over-allocating here can create a large amount of GC pressure so we try to keep
			// it as contained as possible
			 := len() - 
			 := 256 +  +  + >>2
			// Clamp to max block size.
			if + >  {
				 =  - 
			}
			 = append(, make([]byte, )...)
			 = [:len()-]
		}
		if  > maxMatchLen {
			return fmt.Errorf("match len (%d) bigger than max allowed length", )
		}

		// Add literals
		 = append(, .literals[:]...)
		.literals = .literals[:]

		if  == 0 &&  > 0 {
			return fmt.Errorf("zero matchoff and matchlen (%d) > 0", )
		}

		if  > len()+len() ||  > .windowSize {
			if len(.dict) == 0 {
				return fmt.Errorf("match offset (%d) bigger than current history (%d)", , len()+len()-)
			}

			// we may be in dictionary.
			 := len(.dict) - ( - (len() + len()))
			if  < 0 ||  >= len(.dict) {
				return fmt.Errorf("match offset (%d) bigger than current history (%d)", , len()+len()-)
			}
			 :=  + 
			if  > len(.dict) {
				 = append(, .dict[:]...)
				 -= len(.dict) - 
			} else {
				 = append(, .dict[:]...)
				 = 0
				 = 0
			}
		}

		// Copy from history.
		// TODO: Blocks without history could be made to ignore this completely.
		if  :=  - len();  > 0 {
			// v is the start position in history from end.
			 := len() - 
			if  >  {
				// Some goes into current block.
				// Copy remainder of history
				 = append(, [:]...)
				 -= 
			} else {
				 = append(, [:+]...)
				 = 0
			}
		}
		// We must be in current buffer now
		if  > 0 {
			 := len() - 
			if  <= len()- {
				// No overlap
				 = append(, [:+]...)
			} else {
				// Overlapping copy
				// Extend destination slice and copy one byte at the time.
				 = [:len()+]
				 := [ : +]
				// Destination is the space we just added.
				 := [len()-:]
				 = [:len()]
				for  := range  {
					[] = []
				}
			}
		}
		if  == 0 {
			// This is the last sequence, so we shouldn't update state.
			break
		}

		// Manually inlined, ~ 5-20% faster
		// Update all 3 states at once. Approx 20% faster.
		 := .nbBits() + .nbBits() + .nbBits()
		if  == 0 {
			 = [.newState()&maxTableMask]
			 = [.newState()&maxTableMask]
			 = [.newState()&maxTableMask]
		} else {
			 := .get32BitsFast()

			 := uint16( >> ((.nbBits() + .nbBits()) & 31))
			 = [(.newState()+)&maxTableMask]

			 = uint16( >> (.nbBits() & 31))
			 &= bitMask[.nbBits()&15]
			 = [(.newState()+)&maxTableMask]

			 = uint16() & bitMask[.nbBits()&15]
			 = [(.newState()+)&maxTableMask]
		}
	}

	if  := len(.literals) + len() - ;  >  {
		return fmt.Errorf("output bigger than max block size (%d)", )
	}

	// Add final literals
	.out = append(, .literals...)
	return .close()
}

var bitMask [16]uint16

func init() {
	for  := range bitMask[:] {
		bitMask[] = uint16((1 << uint()) - 1)
	}
}

func ( *sequenceDecs) ( *bitReader, , ,  decSymbol) (, ,  int) {
	// Final will not read from stream.
	,  := .final()
	,  := .final()
	,  := .final()

	// extra bits are stored in reverse order.
	.fill()
	 += .getBits()
	if .maxBits > 32 {
		.fill()
	}
	// matchlength+literal length, max 32 bits
	 += .getBits()
	 += .getBits()
	 = .adjustOffset(, , )
	return
}

func ( *sequenceDecs) (,  int,  uint8) int {
	if  > 1 {
		.prevOffset[2] = .prevOffset[1]
		.prevOffset[1] = .prevOffset[0]
		.prevOffset[0] = 
		return 
	}

	if  == 0 {
		// There is an exception though, when current sequence's literals_length = 0.
		// In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
		// an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
		++
	}

	if  == 0 {
		return .prevOffset[0]
	}
	var  int
	if  == 3 {
		 = .prevOffset[0] - 1
	} else {
		 = .prevOffset[]
	}

	if  == 0 {
		// 0 is not valid; input is corrupted; force offset to 1
		println("temp was 0")
		 = 1
	}

	if  != 1 {
		.prevOffset[2] = .prevOffset[1]
	}
	.prevOffset[1] = .prevOffset[0]
	.prevOffset[0] = 
	return 
}