package downloader

import (
	
	

	

	
)

type block struct {
	chunk
	offset   int64
	partSize int
}

// last compares partSize and chunk length to determine last part.
func ( block) () bool {
	// If returned chunk is smaller than requested part, it seems
	// it is last part.
	return len(.data) < .partSize
}

type reader struct {
	sch      schema    // immutable
	verifier *verifier // immutable
	partSize int       // immutable

	offset    int64
	offsetMux sync.Mutex
}

func ( schema,  *verifier) *reader {
	return &reader{
		sch:      ,
		verifier: ,
	}
}

func ( schema,  int) *reader {
	return &reader{
		sch:      ,
		partSize: ,
	}
}

func ( *reader) ( context.Context) (block, error) {
	if .verifier != nil {
		return .nextHashed()
	}

	return .nextPlain()
}

func ( *reader) ( context.Context) (block, error) {
	// Fetch next hashes.
	, ,  := .verifier.next()
	if  != nil {
		return block{}, 
	}
	if ! {
		return block{}, nil
	}

	// Get next chunk.
	,  := .next(, .Offset, .Limit)
	if  != nil {
		return block{}, 
	}

	// Verify chunk.
	if !.verifier.verify(, .data) {
		return block{}, ErrHashMismatch
	}

	return , nil
}

func ( *reader) ( context.Context) (block, error) {
	.offsetMux.Lock()
	 := .offset
	.offset += int64(.partSize)
	.offsetMux.Unlock()

	return .next(, , .partSize)
}

func ( *reader) ( context.Context,  int64,  int) (block, error) {
	 := 0
	for {
		,  := .sch.Chunk(, , )

		if ,  := tgerr.FloodWait(, );  != nil {
			if  || isRetryableTimeout(, ) {
				++
				reportSchemaRetry(.sch, RetryOperationReaderChunk, , )
				continue
			}
			return block{}, errors.Wrap(, "get next chunk")
		}

		return block{
			chunk:    ,
			offset:   ,
			partSize: .partSize,
		}, nil
	}
}