// Copyright 2021 The ebml-go authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ebml

import (
	"bytes"
	"io"
)

type rollbackReader interface {
	Set(io.Reader)
	Get() io.Reader
	Read([]byte) (int, error)
	Reset()
	RollbackTo(int)
}

type rollbackReaderImpl struct {
	io.Reader
	buf []byte
}

func (r *rollbackReaderImpl) Set(v io.Reader) {
	r.Reader = v
}

func (r *rollbackReaderImpl) Get() io.Reader {
	return r.Reader
}

func (r *rollbackReaderImpl) Read(b []byte) (int, error) {
	n, err := r.Reader.Read(b)
	r.buf = append(r.buf, b[:n]...)
	if n != 0 && err == io.EOF {
		err = nil
	}
	return n, err
}

func (r *rollbackReaderImpl) Reset() {
	r.buf = r.buf[0:0]
}

func (r *rollbackReaderImpl) RollbackTo(i int) {
	buf := r.buf
	r.Reader = io.MultiReader(
		bytes.NewReader(buf[i:]),
		r.Reader,
	)
	r.buf = nil
}

type rollbackReaderNop struct {
	io.Reader
}

func (r *rollbackReaderNop) Set(v io.Reader) {
	r.Reader = v
}

func (r *rollbackReaderNop) Get() io.Reader {
	return r.Reader
}

func (r *rollbackReaderNop) Read(b []byte) (int, error) {
	n, err := r.Reader.Read(b)
	if n != 0 && err == io.EOF {
		err = nil
	}
	return n, err
}

func (*rollbackReaderNop) Reset() {
}

func (*rollbackReaderNop) RollbackTo(i int) {
	panic("can't rollback nop rollback reader")
}
