package extraio

import (
	
)

// TailReader buffers the last n bytes read from the underlying io.Reader. That
// is, its Read method does not return last n bytes read. Use Tail method to get
// the underlying buffer on EOF.
//
// Note that its Read method may return zero byte count with a nil error if read
// bytes fit into the underlying buffer. Some io.Reader client implementations
// return io.ErrNoProgress error when many calls to Read have failed to return
// any data or error.
type TailReader struct {
	reader io.Reader

	cur int    // mutable
	buf []byte // mutable
}

// NewTailReader returns a new reader that buffers last n bytes read from r.
func ( io.Reader,  uint) *TailReader {
	var  []byte
	if  != 0 {
		 = make([]byte, 0, )
	}
	return &TailReader{
		reader: ,
		buf:    ,
	}
}

// Reset resets the reader’s state.
func ( *TailReader) () {
	.buf = .buf[:0]
}

// Length returns the length of the underlying buffer. It is faster than calling
// len(r.Tail()) since the underlying buffer may not be contiguous and Tail has
// to linearize it to return a contiguous slice of bytes.
func ( *TailReader) () int {
	return len(.buf)
}

// Tail returns the buffer with last read bytes. The underlying buffer may not
// be contiguous and Tail linearizes the contents before returning a contiguous
// byte slice.
func ( *TailReader) () []byte {
	.linearize()
	return .buf
}

// Read implements the io.Reader interface. It reads from the underlying
// io.Reader but keeps the last n read bytes in the internal ring buffer.
func ( *TailReader) ( []byte) (int, error) {
	,  := .reader.Read()
	if  <= 0 || .buf == nil {
		return , 
	}

	 := cap(.buf)
	 := len(.buf)
	 :=  - 

	switch {
	// Case 1. Data fits into the free buffer space.
	case  <= :
		.buf = append(.buf, [:]...)
		 = 0
	// Case 2. Data exceeds buffer capacity.
	case  >= :
		if  == 0 {
			rotate([:], -)
			 := .buf[.cur:]
			 := .buf[:.cur]
			swap([len():], )
			swap(, )
		} else {
			swap(.buf, [-:])
			.buf = .buf[:]
			copy(.buf[:], [-:])
			 -= 
			rotate([:], -)
		}
	// Case 3. Not enough free space but data fits into the buffer.
	default:
		if  == 0 {
			 := swap(.buf[.cur:], [:])
			.cur = (.cur + ) % 
			 = swap(.buf[.cur:], [:])
			.cur = (.cur + ) % 
		} else {
			.buf = append(.buf, [:]...)
			copy(, [:])
			 -= 
			swap(.buf, [:])
			.cur = 
		}
	}
	return , 
}

// linearize makes the underlying ring buffer contiguous.
func ( *TailReader) () {
	rotate(.buf, .cur)
	.cur = 0
}

// swap swaps elements between dst and src slices. It returns the number of
// swapped elements, that is, min(len(dst), len(src)).
func (,  []byte) int {
	 := min(len(), len())
	for  := 0;  < ; ++ {
		[], [] = [], []
	}
	return 
}

// rotate performs in-place left rotation of the slice by n positions from the
// start for positive n. If n is negative, the slice is right rotated by the
// absolute value of n.
//
// Examples:
//
//   rotate([]byte("lohel"), 2)
//       => []byte("hello")
//
//   rotate([]byte("45123"), 2)
//       => []byte("12345")
//
//   rotate([]byte("34512"), -2)
//       => []byte("12345")
//
func ( []byte,  int) {
	 := len()
	if  == 0 ||  == 1 {
		return
	}

	 %= 
	if  == 0 ||  ==  {
		return
	}

	if  < 0 {
		 += 
	}

	reverse([:])
	reverse([:])
	reverse()
}

// reverse performs in-place reversal of the slice.
func ( []byte) {
	for ,  := 0, len()-1;  < ; ,  = +1, -1 {
		[], [] = [], []
	}
}

// min returns the minimum of the two integers.
func (,  int) int {
	if  <  {
		return 
	}
	return 
}